摘要

Spring MVC 是一个 MVC 开源框架,用来代替 Struts。它是 Spring 项目里面的一个重要组成部分,能与 Spring IOC 容器紧密结合,以及拥有松耦合、方便配置、代码分离等特点,让 JAVA 程序员开发 WEB 项目变得更加容易。

Spring MVC的异常处理 ?

1.web.xml中异常处理

通常为了给用户提供良好的人机接口,我们都会为整个web应用,提供处理异常或者 错误的通用页面,而这些通用页面需要在web.xml中进行配置。主要是两种方式:其一根据HTTP响应状态码;其二是根据异常类名进行配置。

<error-page> 
     <exception-type>完整的异常类名</exception-type> 
     <location>以”/”开头的异常处理页面路径</location> 
  </error-page> 
  <error-page> 
     <error-code>HTTP响应状态码</error-code> 
     <location>以”/”开头的异常处理页面路径</location> 
  </error-page>

2.在springmvc上配置全局异常(配置文件的方式)

在spring-servlet.xml(springmvc的配置文件)中配置

<!-- Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver-全局异常配置 start -->     
      <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
       <!--   默认的错误信息页面 -->
        <property name="defaultErrorView" value="error"/>
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.NullPointerException">commons/error/error_spring_null</prop>
                <prop key="java.lang.ArithmeticException">commons/error/error_spring_math</prop>
            </props>
        </property>
    </bean>   
     <!-- 全局异常配置 end -->
@Controller
@RequestMapping(value="/exception")
public class TestException {

	@RequestMapping("/exception/{id}")
    @ResponseBody
    public Object hello(@PathVariable String id)  {

        if (id.equals("1")) {//NullPointerException控制值异常
            throw new NullPointerException("空指针异常");
        } else if (id.equals("2")) {//数学运算异常
            int value = 1 / 0;
            return "java.lang.ArithmeticException";
        } else {
            return "ok";
        }
    }

总结点:如果同时使用web.xml和spring-servlet.xml配置同样的异常,会出现什么结果,web.xml 和spring-servlet.xml配置会不会冲突?

这涉及到web.xml中元素的加载顺序,元素节点的加载顺序与它们在 web.xml 文件中的先后顺序无关,通常是ServletContext -> listener -> filter -> servlet---->------>error-page.。

<!-- springmvc -->
	<servlet>
		<servlet-name>spring</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 自定义spring mvc的配置文件名称和路径 -->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springMVC/spring-servlet.xml</param-value>
		</init-param>
		<!-- 自定义启动顺序,让这个Servlet随Servlet容器一起启动 -->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
		<!-- 异常处理 -->
	<!-- 接收空指针错误 -->
	<error-page>
		<exception-type>java.lang.NullPointerException</exception-type>
		<location>/WEB-INF/views/commons/error/error_web_null.jsp</location>
	</error-page>
	<!-- 404 页面不存在错误 -->
	<error-page>
		<error-code>404</error-code>
		<location>/WEB-INF/views/commons/error/error_web_404.jsp</location>
	</error-page>
	<!-- 接收405错误 -->
	<error-page>
		<error-code>405</error-code>
		<location>/WEB-INF/views/commons/error/error405.jsp</location>
	</error-page>
	<!--  500 服务器内部错误 -->
	<error-page>
		<error-code>500</error-code>
		<location>/WEB-INF/views/commons/error/error500.jsp</location>
	</error-page>

结果显而易见,spring-servlet.xml的加载顺序比error-page的快,异常会当有相同配置的错误时,会优先spring-servlet.xml中配置。只有当spring-servlet.xml没有处理的错误异常,才会在web.xml的error-page节点中查找对应异常。

spring-servlet.xml采用配置文件的方式的缺点:配置文件可以根据抛出的异常类的类信息配置错误的页面。但是这样我们无法手动对其定制异常。故出现第三种方式

第三种方式采用自定义异常类,定制异常集中处理

//自己手动编写Java代码来实现定制异常信息处理
package com.util.exception;
/**
 * 所属类别:工具类
 * 用途:自定义的异常类
 * @author yilei
 * version:1.0
 */
public class ExceptionUtil extends RuntimeException {
	public ExceptionUtil(String string) {
		super(string);
	}
}
<!-- Spring MVC提供的简单异常处理器SimpleMappingExceptionResolver-全局异常配置 start -->     
      <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
       <!--  默认的错误信息页面-->
        <property name="defaultErrorView" value=">commons/error/error"/>
        <property name="exceptionMappings">
            <props>
                <!-- 自定义的异常类 -->
                <prop key="com.util.exception.ExceptionUtil">commons/error/error_spring_ExceptionUtil</prop> 
                <!-- 空指针异常 -->
                <prop key="java.lang.NullPointerException">commons/error/error_spring_null</prop>
                <!-- 数学算术异常 -->
                <prop key="java.lang.ArithmeticException">commons/error/error_spring_math</prop>
            </props>
        </property>
    </bean>    
     <!-- 全局异常配置 end -->

error_spring_ExceptionUtil.jsp 自定义异常处理jsp页面

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
error_spring_ExceptionUtil.jsp<br>
spirngmvc配置异常-自定义异常
</body>
</html>

TestException.java 进行异常测试的类,throw new ExceptionUtil(“自定义有异常”);这段代码用于抛出自定义异常类,springmvc中配置自动跳转到commons/error/error_spring_ExceptionUtil页面

package com.controller.test.exception;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.util.exception.ExceptionUtil;

@Controller
@RequestMapping(value = "/exception")
public class TestException   {

	@RequestMapping("/exception/{id}")
	@ResponseBody
	public Object hello(@PathVariable String id) {
        if(id.equals("0")){
        	 throw new ExceptionUtil("自定义有异常");
        }else if (id.equals("1")) {// NullPointerException控制值异常
			throw new NullPointerException("空指针异常");
		} else if (id.equals("2")) {// 数学运算异常
			int value = 1 / 0;
			return "java.lang.ArithmeticException";
		} else {
			return "ok";
		}
	}
}

第四种方式去实现自定义异常处理(基于注解的方式)

TestException.java 异常测试类,使用注解ExceptionHandler来标识,在每个需要使用此异常处理的类中添加handleLocalException方法,在使用 throw new ExceptionUtil(“自定义有异常”);代码时候,就算同时配置上面第三种方法来自定义了异常处理界面,但是也不会生效,而是由方法handleLocalException中决定异常处理结果,本类中最终有error.jsp页面来进行异常显示。

package com.controller.test.exception;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.util.exception.ExceptionUtil;

@Controller
@RequestMapping(value = "/exception")
public class TestException   {

	@RequestMapping("/exception/{id}")
	@ResponseBody
	public Object hello(@PathVariable String id) {
        if(id.equals("0")){
        	 throw new ExceptionUtil("自定义有异常");
        }else if (id.equals("1")) {// NullPointerException控制值异常
			throw new NullPointerException("空指针异常");
		} else if (id.equals("2")) {// 数学运算异常
			int value = 1 / 0;
			return "java.lang.ArithmeticException";
		} else {
			return "ok";
		}
	}
    //异常处理,基于注解的方式,但是需要进行自定义异常的类中都写一个相同的方法才可生效。如果使用这种方式。
    @ExceptionHandler(value={ExceptionUtil.class})
    public String handleLocalException(ExceptionUtil e, HttpServletRequest req){
        req.setAttribute("error", e);
        return "error/error";
    }
}

第一种web.xml配置和第二种基于springmvc中配置的方式是最常见的异常处理方法,通常项目中是结合一起使用

第三种和第四中方式主要是为了定制异常,为了满足项目上一些特殊需求,

相对第四种方式,更建议采用第三种的方式来自定义异常处理,主要是因为第四种(采用注解的方式),需要在每个使用了自定义异常类中都需要类似以下代码的方法来处理异常,对程序来说比较冗余。

而第三种,在第二种方法的基础上,实现全局的配置,更便捷,因此,如果需要使用自定义异常的话,建议使用第三种方式,同时第一种和第二种相结合

SpringMVC中的拦截器问题 ?

springMVC中的拦截器是相当有用的,能够在用户进行请求后,进入具体的业务代码controller方法之前,进行相关操作,例如接口验签,判断登录状态,权限控制等等,也可以在处理完controller方法,进行视图渲染前,对返回视图的数据进行处理,也能够对整个请求结束后,进行资源的释放等功能。

一. 使用场景

  • 1、日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV(Page View)等。
  • 2、权限检查:如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面;
  • 3、性能监控:有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间(如果有反      向代理,如apache可以自动记录);
  • 4、通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实      现。
  • 5、OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。

本质也是AOP(面向切面编程),也就是说符合横切关注点的所有功能都可以放入拦截器实现。

一、定义Interceptor实现类

springMVC的拦截器主要通过HandlerInterceptor来实现的。在springMVC中定义一个拦截器interceptor十分简单,可以通过两种方法来实现。

  • 一种是直接实现spring的HandlerInterceptor接口,或者继承spring提供的已经继承了该接口的抽象类HandlerInterceptorAdapter;
  • 另一种是要实现Spring的WebRequestInterceptor接口,或者是继承实现了WebRequestInterceptor的类。

实现HandlerInterceptor接口或继承实现该接口的类

HandlerInterceptor中定义了三个方法,有不同的执行顺序:

1、preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):该方法是在客户端发起请求后,进入到具体的方法前进行调用。springMVC中拦截器的调用是链式的,一个应用或一个请求中可以有多个拦截器,会根据在配置文件中的声明顺序来进行处理,当然,每次进入拦截器后,都会先调用prehandle方法。该方法的返回值为boolean类型,只有当返回值未true时,才会执行后续操作,若后面还有拦截器,则继续调用下一个拦截器的prehandle,直到最后一个拦截器的prehandle方法处理完,就会进入对应的controller方法,如果返回false,则会结束请求。所以,可以在该方法中处理一些前置任务,比如接口验签,解密,权限控制等操作。

2、postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView):该方法的执行时间是在执行完controller的方法后,返回到视图渲染前的阶段。所以,该方法能够对返回前端的ModelAndView数据进行处理。需要注意的是,当有多个拦截器的时候,posthandle方法的执行顺序和prehandle是相反的,先声明的拦截器的posthandle方法反而会后执行。

3、afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex):该方法的执行时间是在完成请求,也完成了视图渲染后进行调用。和posthandle一样,当有多个拦截器时,也是先声明的后执行规则。该方法因为是在完成请求后执行,所以对请求无法进行操作,一般是用来进行资源的释放等操作。

/**
 * 
 */
package com.charlotte.blog.interceptor;

import java.io.PrintWriter;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * @author dingjunjie
 * @date 2018-02-07 12:51:30
 * @desc spring拦截器,继承HandlerInterceptorAdapter抽象类
 */
public class SpingMvcInterceptor extends HandlerInterceptorAdapter {

    /**
     * springMVC接收到请求,在访问controller前自动执行该方法
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("执行了:preHandle========");
        return true;
    }

    /**
     * 在执行完controller方法后,进行视图渲染前自动调用该方法
     */
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("执行了:postHandle=========:");
    }

    /**
     * 在视图渲染完成后,自动调用,主要用于清理数据
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("执行了:afterCompletion====");
    }

    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
    }
}

实现WebRequestInterceptor接口

WebRequestInterceptor接口中也定义了三个接口,和HandlerInterceptor接口类似,不同的是,这三个方法都有一个共同的参数WebRequest。这个WebRequest 是Spring 定义的一个接口,它里面的方法定义都基本跟HttpServletRequest 一样,在WebRequestInterceptor 中对WebRequest 进行的所有操作都将同步到HttpServletRequest 中,然后在当前请求中一直传递。

1、preHandle(WebRequest arg0):该方法的执行顺序和HandlerInterceptor的一样,不再赘述。不同的是它没有返回值,而且参数类型为WebRequest。需要注意的是,WebRequest的setAttribute(name, value, scope)方法有三个参数,主要是第三个参数,在WebRequest 的父层接口RequestAttributes 中对它定义了三个常量:

SCOPE_REQUEST :它的值是0 ,代表只有在request 中可以访问。
SCOPE_SESSION :它的值是1 ,如果环境允许的话它代表的是一个局部的隔离的session,否则就代表普通的session,并且在该session范围内可以访问。
SCOPE_GLOBAL_SESSION :它的值是2 ,如果环境允许的话,它代表的是一个全局共享的session,否则就代表普通的session,并且在该session 范围内可以访问。

2、postHandle(WebRequest arg0, ModelMap arg1):该方法有两个参数,WebRequest 对象是用于传递整个请求数据的,比如在preHandle 中准备的数据都可以通过WebRequest 来传递和访问;ModelMap 就是Controller 处理之后返回的Model 对象,我们可以通过改变它的属性来改变返回的Model 模型。

3、afterCompletion(WebRequest arg0, Exception arg1):该方法会在整个请求处理完成,也就是在视图返回并被渲染之后执行。所以在该方法中可以进行资源的释放操作。而WebRequest 参数就可以把我们在preHandle 中准备的资源传递到这里进行释放。Exception 参数表示的是当前请求的异常对象,如果在Controller 中抛出的异常已经被Spring 的异常处理器给处理了的话,那么这个异常对象就是是null 。

/**
 * 
 */
package com.charlotte.blog.interceptor;

import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;

/**
 * @author dingjunjie
 * @date 2018-02-07 16:26:30
 */
public class WebInterceptor implements WebRequestInterceptor{

    /* (non-Javadoc)
     * @see org.springframework.web.context.request.WebRequestInterceptor#afterCompletion(org.springframework.web.context.request.WebRequest, java.lang.Exception)
     */
    @Override
    public void afterCompletion(WebRequest arg0, Exception arg1) throws Exception {
        System.out.println(getClass().getSimpleName() + "执行了:afterCompletion");
    }

    /* (non-Javadoc)
     * @see org.springframework.web.context.request.WebRequestInterceptor#postHandle(org.springframework.web.context.request.WebRequest, org.springframework.ui.ModelMap)
     */
    @Override
    public void postHandle(WebRequest arg0, ModelMap arg1) throws Exception {
        System.out.println(getClass().getSimpleName() + "执行了:postHandle");
    }

    /* (non-Javadoc)
     * @see org.springframework.web.context.request.WebRequestInterceptor#preHandle(org.springframework.web.context.request.WebRequest)
     */
    @Override
    public void preHandle(WebRequest arg0) throws Exception {
        System.out.println(getClass().getSimpleName() + "执行了:preHandle");
    }

}

拦截器配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:mvc="http://www.springframework.org/schema/mvc"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
                        http://www.springframework.org/schema/context    
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd    
                        http://www.springframework.org/schema/mvc    
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->  
    <context:component-scan base-package="com.charlotte.blog.controller" />

    <mvc:annotation-driven>
        <mvc:message-converters register-defaults="true">
            <bean class="com.charlotte.sdk.common.beans.MyFastJsonHttpMessageConverter">
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html;charset=UTF-8</value>
                        <value>application/json</value>
                    </list>
                </property>
                <property name="features">
                    <array value-type="com.alibaba.fastjson.serializer.SerializerFeature">
                        <value>DisableCircularReferenceDetect</value>
                        <!--<value>UseISO8601DateFormat</value>-->
                        <value>WriteMapNullValue</value>
                        <value>WriteNullListAsEmpty</value>
                        <value>WriteNullStringAsEmpty</value>
                        <value>WriteNullBooleanAsFalse</value>
                    </array>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>

    <!-- springMVC拦截器配置 -->
    <mvc:interceptors>
        <!-- 直接定义在 mvc:interceptors根下的bean会拦截所有请求-->
        <bean class="com.charlotte.blog.interceptor.WebInterceptor"/>
        <mvc:interceptor>
            <!-- 定义在 mvc:interceptor下的bean会根据mvc:mapping中配置的路径来进行匹配拦截-->
            <mvc:mapping path="/**"/>
            <bean class="com.charlotte.blog.interceptor.SpingMvcInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>
//doDispatch方法  
//1、处理器拦截器的预处理(正序执行)  
HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();  
if (interceptors != null) {  
    for (int i = 0; i < interceptors.length; i++) {  
    HandlerInterceptor interceptor = interceptors[i];  
        if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {  
            //1.1、失败时触发afterCompletion的调用  
            triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);  
            return;  
        }  
        interceptorIndex = i;//1.2、记录当前预处理成功的索引  
}  
}  
//2、处理器适配器调用我们的处理器  
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  
//当我们返回null或没有返回逻辑视图名时的默认视图名翻译(详解4.15.5 RequestToViewNameTranslator)  
if (mv != null && !mv.hasView()) {  
    mv.setViewName(getDefaultViewName(request));  
}  
//3、处理器拦截器的后处理(逆序)  
if (interceptors != null) {  
for (int i = interceptors.length - 1; i >= 0; i--) {  
      HandlerInterceptor interceptor = interceptors[i];  
      interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);  
}  
}  
//4、视图的渲染  
if (mv != null && !mv.wasCleared()) {  
render(mv, processedRequest, response);  
    if (errorView) {  
        WebUtils.clearErrorRequestAttributes(request);  
}  
//5、触发整个请求处理完毕回调方法afterCompletion  
triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);

Spring MVC如何解决中文乱码问题 ?

表单提交controller获得中文参数后乱码解决方案。注意: jsp页面编码设置为UTF-8。form表单提交方式为必须为post,get方式下面spring编码过滤器不起效果。

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<form action="${ctx}/user/addUser" name="userForm" method="post">
<filter>
<filter-name>characterEncodingFilter</filter-name>
	<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value>
	</init-param>
	<init-param>
		<param-name>forceEncoding</param-name>
		<param-value>true</param-value>
	</init-param>
	</filter>
	<filter-mapping>
    	<filter-name>characterEncodingFilter</filter-name>
    	<url-pattern>/*</url-pattern>
</filter-mapping>

get请求中文参数出现乱码解决方法有两个:

①修改tomcat配置文件添加编码与工程编码一致,如下:

<ConnectorURIEncoding="utf-8"connectionTimeout="20000"port="8080"protocol="HTTP/1.1"redirectPort="8443"/>

②另外一种方法对参数进行重新编码:ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码。

StringuserName =newString(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")

Spring MVC如何向页面传值 ?

    (1)使用request绑订数据

    (2)使用ModelAndView

    (3)使用ModelMap

    (4)使用session绑订数据

package controller;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
 
/**
 * 二级控制器:
 *   负责业务逻辑的处理。
 *  1.不用实现Controller接口
 *  2.在一个Controller类里面,可以添加
 *  多个处理方法
 *     这些方法的方法名可以自定义,返回值
 *   可以是ModelAndView或者是String。
 *   http://ip:port/springmvc02/hello.do
 */
@Controller("hc")
public class HelloController {
	
	@RequestMapping("/login4.do")
	//向页面传值的第一种方式:使用request绑订数据
	public String login4(User user,
			HttpServletRequest req){
		System.out.println("login4方法...");
		System.out.println(
				user.getUsername() 
				+ " " + user.getPwd());
		req.setAttribute("user", 
				user);
		//默认情况下,使用转发的方式来跳转页面。
		return "success";
	}
	
	@RequestMapping("/login5.do")
	//向页面传值的第二种方式,使用ModelAndView
	public ModelAndView login5(User user){
		System.out.println("login5方法...");
		System.out.println(
				user.getUsername() 
				+ " " + user.getPwd());
		//ModelAndView(
		//String viewName,Map data)
		Map<String,Object> data = 
			new HashMap<String,Object>();
		//相当于执行了request.setAttribute(
		//"user",user);
		data.put("user", user);
		return new ModelAndView(
				"success",data);
	}
	
	@RequestMapping("/login6.do")
	//向页面传值的第三种方式,使用ModelMap
	public String login6(User user,
			ModelMap data){
		System.out.println("login6方法...");
		System.out.println(
				user.getUsername() 
				+ " " + user.getPwd());
		//相当于request.setAttribute("user",user)
		data.addAttribute("user", user);
		return "success";
	}
	
	@RequestMapping("/login7.do")
	//向页面传值的第四种方式:使用session绑订数据
	public String login7(User user,
			HttpSession session){
		System.out.println("login7方法...");
		System.out.println(
				user.getUsername() 
				+ " " + user.getPwd());
		session.setAttribute("user", user);
		return "success";
	}
}

SpringMVC如何读取请求参数值 ?

方式一 通过request

@RequestMapping("/login.do")
    /*
     * (了解)
     * DispatcherServlet在调用Controller
     * 的方法之前,会利用java反射机制分析
     * 方法的结构,然后将需要的对象作为参数
     * 传递过来(并如将request对象作为参数
     * 传递过来)。
     */
    public String login(HttpServletRequest request){
        System.out.println("login()");
        String adminCode=request.getParameter("adminCode");
            //获取到界面上name = pwd的值
        String pwd = 
            request.getParameter("pwd");
        System.out.println("adminCode:" 
            + adminCode + " pwd:" + pwd);
        return "index";
    }

通过@RequestParam

@RequestMapping("/login2.do")
    /*
     * 形参名要与请求参数名一致。
     * 如果不一致,使用@RequestParam。
     */
    public String login2(String adminCode,@RequestParam("pwd") String password){
        System.out.println("login()");
        System.out.println("adminCode:" 
                + adminCode + " pwd:" 
                + password);
        return "index";
    }

方式三 通过javabean

@RequestMapping("/login3.do")
    public String login3(AdminParam ap){
    //AdminParam属性和界面定义的控件的name名一致
        System.out.println("login3()");
        System.out.println("adminCode:" 
        + ap.getAdminCode() + " pwd:"
                + ap.getPwd());
        return "index";
    }

SpringMVC怎样设定重定向和转发 ?

一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理。如果返回的字符串中带 forward: 或 redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和redirect: 当成指示符,其后的字符串作为 URL 来处理。

(1)转发:在返回值前面加"forward:",譬如"forward:user.do?name=method4"

(2)重定向:在返回值前面加"redirect:",譬如"redirect:http://www.baidu.com"

@RequestMapping("/springMvc")
@Controller
public class handler {
    //测试重定向
    @RequestMapping("/testRedirect")
    public String testRedirect(){
        System.out.println("testRedirect");
        return "redirect:/index.jsp";
    }
 
}
@RequestMapping("/springMvc")
@Controller
public class handler {
    //测试转发
    @RequestMapping("/testRedirect")
    public String testRedirect(){
        System.out.println("testRedirect");
        return "forward:/index.jsp";
    }
 
}

转发与重定向的区别

    地址栏

  •     转发:不变,不会显示出转向的地址
  •     重定向:会显示转向之后的地址

    请求

  •     转发:一次请求
  •     重定向:至少提交了两次请求

    数据:

  •     转发:对request对象的信息不会丢失,因此可以在多个页面交互过程中实现请求数据的共享
  •     重定向:request信息将丢失

    原理:

  •     转发:是在服务器内部控制权的转移,是由服务器区请求,客户端并不知道是怎样转移的,因此客户端浏览器的地址不会显示出转向的地址。
  •     重定向:是服务器告诉了客户端要转向哪个地址,客户端再自己去请求转向的地址,因此会显示转向后的地址,也可以理解浏览器至少进行了两次的访问请求。

转发和重定向的流程

  • 重定向的流程: 浏览器发送请求->服务器运行->相应请求------->,返回给浏览器一个新的地址与响应码,浏览器进行判断为重定向,自动发送一个新的请求给服务器,请求地址为刚刚服务器发送给浏览器的地址。->服务器运行->相应请求
  • 转发的流程: 发送请求 -->服务器运行–>进行请求的重新设置,例如通过request.setAttribute(name,value)–>根据转发的地址,获取该地址的网页–>响应请求给浏览器

SpringMvc的控制器是不是单例模式,如果是,有什么问题,怎么解决

是单例模式,所以在多线程访问的时候有线程安全问题,不要用同步,会影响性能的,解决方案是在控制器里面不能写字段

SpingMvc中的控制器的注解一般用那个,有没有别的注解可以替代

答:一般用@Controller注解,也可以使用@RestController,@RestController注解相当于@ResponseBody + @Controller,表示是表现层,除此之外,一般不用别的注解代替。

@RequestMapping注解用在类上面有什么作用

用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

怎么样把某个请求映射到特定的方法上面

直接在方法上面加上注解@RequestMapping,并且在这个注解里面写上要拦截的路径

如果在拦截请求中,我想拦截get方式提交的方法,怎么配置

可以在@RequestMapping注解里面加上method=RequestMethod.GET

如果在拦截请求中,我想拦截提交参数中包含”type=test”字符串,怎么配置

可以在@RequestMapping注解里面加上params=”type=test”

我想在拦截的方法里面得到从前台传入的参数,怎么得到

直接在形参里面声明这个参数就可以,但必须名字和传过来的参数一样

如果前台有很多个参数传入,并且这些参数都是一个对象的,那么怎么样快速得到这个对象

直接在方法中声明这个对象,SpringMvc就自动会把属性赋值到这个对象里面

怎么样在方法里面得到Request,或者Session

直接在方法的形参中声明request,SpringMvc就自动把request对象传入。

SpringMvc中函数的返回值是什么

返回值可以有很多类型,有String、ModelAndView、JSON。ModelAndView类把视图和数据都合并的一起的,但一般用String比较好。

怎么样把ModelMap里面的数据放入Session里面

可以在类上面加上@SessionAttributes注解,里面包含的字符串就是要放入session里面的key