Spring MVC (一)

1. 概述

  • Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的 MVC 框架之一。
  • Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架。
  • Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任何接口。
  • 支持 REST 风格的 URL 请求。
  • 采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。

1.1 HelloWorld例子

  • 配 置 DispatcherServlet :DispatcherServlet 默 认 加 载 /WEB- INF/<servletName-servlet>.xml 的 Spring 配置文件, 启动 WEB 层的 Spring 容器。可以通过 contextConfigLocation 初始化参数自定义配置文件的位置和名称。
    <servlet>
        <servlet-name>springDispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext-mvc.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>springDispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  • 配置applicationContext-mvc.xml

    • 配置自动扫描的包
    <context:component-scan base-package="com.chen.demo"/>
    • 配置视图解析器把controller方法返回值解析为实际的地址
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
  • 创建处理请求的controller

    @Controller
    public class HelloWorld {
        @RequestMapping("/hello")
        public String hello(){
        System.out.println("hello world!");
            return "success";
        }
    }
    

2. 使用 @RequestMapping 映射请求

2.1 概述

  • Spring MVC 使用 @RequestMapping 注解为控制器指定可以处理哪些 URL 请求。
  • 在控制器的类定义及方法定义处都可标注@RequestMapping
    • 类定义处:提供初步的请求映射信息。相对于 WEB 应用的根目录
    • 方法处:提供进一步的细分映射信息;相对于类定义处的 URL。若类定义处未标注 @RequestMapping,则方法处标记的 URL 相对于 WEB 应用的根目录
  • DispatcherServlet 截获请求后,就通过控制器上@RequestMapping 提供的映射信息确定请求所对应的处理方法。
  • controller代码如下

    @RequestMapping("/springMVC")
    @Controller
    public class RequestMappingDemo {

        private static final String SUCCESS = "success";

        @RequestMapping("/testRequestMapping")
        public String testRequestMapping() {
            System.out.println("testRequestMapping");
            return SUCCESS;
        }
    }

2.2. 请求方式、请求头和请求参数

  • @RequestMapping 除了可以使用请求 URL 映射请求外,还可以使用请求方法、请求参数及请求头映射请求
  • @RequestMappingvaluemethodparamsheaders 分别表示请求 URL、请求方法、请求参数及请求头的映射条件,他们之间是与的关系,联合使用多个条件可让请求映射更加精确化
  • params 和 headers支持简单的表达式
    • param1: 表示请求必须包含名为 param1 的请求参数。
    • !param1: 表示请求不能包含名为 param1 的请求参数。
    • param1 != value1: 表示请求包含名为 param1 的请求参数,但其值不能为 value1。
    • {“param1 = value1”,”param2”}: 请求必须包含名为 param1 和param2 的两个请求参数,且 param1 参数的值必须为 value1。
  • 映射请求方式的方法
    @RequestMapping(value = "/testMethod", method = RequestMethod.POST)
    public String testMethod() {
        System.out.println("testMethod");
        return SUCCESS;
    }
  • 映射请求头和请求参数的方法
    @RequestMapping(value = "/testParamsAndHeaders", params = {"userName", "age!=10"},
            headers = {"Accept-Language=zh-CN,zh;q=0.8"})
    public String testParamsAndHeaders() {
        System.out.println("testParamsAndHeaders");
        return SUCCESS;
    }

2.3. @RequestMapping 支持 Ant 风格通配符

  • Ant 风格资源地址支持 3 种匹配符:
    • ?:匹配文件名中的一个字符
    • *:匹配文件名中的任意字符
    • **** 匹配多层路径
  • 处理方法代码
    @RequestMapping("/testAntPath/*/abc")
    public String testAntPath() {
        System.out.println("testAntPath");
        return SUCCESS;
    }

2.4. @PathVariable 映射 URL 绑定的占位符

  • 带占位符的 URL 是 Spring3.0 新增的功能,该功能在 SpringMVC 向 REST 风格目标挺进发展过程中具有里程碑的意义
  • 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过 @PathVariable(“xxx”) 绑定到操作方法的入参中。
  • 处理方法代码
    @RequestMapping("/testPathVariable/{id}")
    public String testPathVariable(@PathVariable(value = "id") Integer id){
        System.out.println("testPathVariable id:"+id);
        return SUCCESS;

    }

3. REST

3.1. 概述

  • REST:即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

  • 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的
    URI 。要获取这个资源,访问它的URI就可以,因此 URI即为每一个资源的独一无二的识别符

  • 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层 (Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON格式表现,甚至可以采用二进制格式。

  • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生” 状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是

3.2. HiddenHttpMethodFilter

  • 浏览器 form 表单只支持 GET 与 POST 请求,而 DELETE、PUT 等 method 并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与DELETE 请求。

  • 在web.xml中配置

    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

3.3. 发送GET、POST、PUT和DELETE请求

  • 1.配置HiddenHttpMethodFilter。
  • 2.发送POST请求。
  • 3.需要在发送POST请求时携带一个name为_method的隐藏域,value为PUTDELETE,如 <input type="hidden" name="_method" value="PUT"/>
  • 处理方法代码
    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.GET)
    public String testRestGET(@PathVariable Integer id){
        System.out.println("testRest GET : "+id);
        return SUCCESS;
    }

    @RequestMapping(value = "/testRest",method = RequestMethod.POST)
    public String testRestPOST(){
        System.out.println("testRest POST ");
        return SUCCESS;
    }

    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.PUT)
    public String testRestPut(@PathVariable Integer id){
        System.out.println("testRest PUT : "+id);
        return SUCCESS;
    }

    @RequestMapping(value = "/testRest/{id}",method = RequestMethod.DELETE)
    public String testRestDelete(@PathVariable Integer id){
        System.out.println("testRest DELETE : "+id);
        return SUCCESS;
    }
  • Jsp 代码
    <%--GET--%>
    <a href="${pageContext.request.contextPath}/springMVC/testRest/1">test REST GET</a>
    <br/>

    <%--POST--%>
    <form action="${pageContext.request.contextPath}/springMVC/testRest" method="post">
      <input type="submit" value="test Rest POST">
    </form>
    <br/>

    <%--PUT--%>
    <form action="${pageContext.request.contextPath}/springMVC/testRest/1" method="post">
      <input type="hidden" name="_method" value="PUT"/>
      <input type="submit" value="test Rest PUT">
    </form>
    <br/>

    <%--DELETE--%>
    <form action="${pageContext.request.contextPath}/springMVC/testRest/1" method="post">
      <input type="hidden" name="_method" value="DELETE"/>
      <input type="submit" value="test Rest DELETE">
    </form>

4. 将请求信息绑定到处理方法的相应入参

4.1. 使用@RequestParam 绑定请求参数

  • 在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法
    • value:参数名
    • required:是否必须。默认为 true, 表示请求参数中必须包含对应的参数,若不存在,将抛出异常
  • 处理方法代码
    @RequestMapping(value = "/testRequestParam")
    public String testRequestParam(@RequestParam(value = "userName")String userName,
                                   @RequestParam(value = "age",required = false,defaultValue ="0")int age){
        System.out.println("testRequestParam userName = "+userName+" age = "+age);
        return SUCCESS;
    }

4.2. 使用 @RequestHeader 绑定请求头的属性值

  • 请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中

  • 处理方法代码

    @RequestMapping(value = "/testRequestHeader")
    public String testRequestHeader(@RequestHeader(value = "Accept-Language")String al){
        System.out.println("testRequestHeader Accept-Language = "+al);
        return SUCCESS;
    }

4.3. @CookieValue 绑定请求中的Cookie值

  • @CookieValue可以让处理方法入参绑定某个Cookie值

  • 处理方法代码

    @RequestMapping("/testCookieValue")
    public String testCookieValue(@CookieValue("JSESSIONID")String sessionId){
        System.out.println("testCookieValue sessionId"+sessionId);
        return SUCCESS;
    }

5. 使用POJO对象绑定请求参数值

  • Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。 如:dept.deptId、dept.address.tel 等。

  • POJO类 - User

public class User {
    private int id;
    private String userName;
    private String password;
    private String email;
    private int age;
    private Address address;

    //省略setter、getter、constructor和toString
    ...
}
  • POJO类 - Address
public class Address {
    private String province;
    private String city;

    //省略setter、getter、constructor和toString
    ...
}
  • JSP代码
    <form action="${pageContext.request.contextPath}/springMVC/testPojo" method="post">
      userName:<input name="userName" type="text"/><br/>
      password:<input name="password" type="password"/><br/>
      email:<input name="email" type="text"/><br/>
      age:<input name="age" type="text"/><br/>
      city:<input name="address.city" type="text"/><br/>
      province:<input name="address.province" type="text"/><br/>
      <input type="submit" value="Submit">
    </form>
  • 处理方法代码
    @RequestMapping("/testPojo")
    public String testPojo(User user){
        System.out.println("testPojo "+user);
        return  SUCCESS;
    }

6. 使用 Servlet API 作为入参

  • MVC的handler方法支持 原生ServletAPI 作为目标方法的参数
    • HttpServletRequest
    • HttpServletResponse
    • HttpSession
    • java.security.Principal
    • Locale
    • InputStream
    • OutputStream
    • Reader
    • Writer
  • 处理方法代码
    @RequestMapping("/testServletAPI")
    public String testServletAPI(HttpServletRequest request,
                                 HttpServletResponse response){
        System.out.println("testServletAPI "+request+" , "+response);
        return  SUCCESS;
    }

7. 处理模型数据

7.1. 概述

  • Spring MVC 提供了以下几种途径输出模型数据:
    • ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添加模型数据。
    • Map 及 Model: 入参为 org.springframework.ui.Modelorg.springframework.ui.ModelMap
      java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。
    • @SessionAttributes: 将模型中的某个属性暂存到HttpSession 中,以便多个请求之间可以共享这个属性。
    • @ModelAttribute: 方法入参标注该注解后, 入参的对象就会放到数据模型中。

7.2. ModelAndView

  • 控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息
  • Spring MVC会把 ModelAndView 的 Model 中数据放到 request 域对象中。
  • 处理方法代码
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        String viewName = SUCCESS;
        ModelAndView modelAndView = new ModelAndView(viewName);

        //添加模型数据到ModelAndView中
        modelAndView.addObject("time",new Date());

        return modelAndView;
    }

7.3. Map及Model

  • 处理方法代码
    @RequestMapping("/testMap")
    public String testMap(Map<String,Object> map){

        //org.springframework.validation.support.BindingAwareModelMap
        System.out.println(map.getClass().getName());

        map.put("names", Arrays.asList("Tom","Jerry","Mike"));
        return SUCCESS;

    }

7.4. @SessionAttribute

  • 若希望在多个请求之间共用某个模型属性数据,则可以控制器类上标注一个 @SessionAttributes, Spring MVC将在模型中对应的属性暂存到 HttpSession 中。
  • @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外,还可以通过模型属性的类型指定哪些模型属性需要放到会话中。
  • 控制器代码
    @SessionAttributes(value = {"user"},types = {String.class})
    @RequestMapping("/springMVC")
    @Controller
    public class RequestMappingDemo {
        private static final String SUCCESS = "success";
        @RequestMapping("/testSessionAttribute")
        public String testSessionAttribute(Map<String,Object> map){
            User user = new User(1,"Tom","123","[email protected]",20);
            //value = {"user"}
            map.put("user",user);
            //types = {String.class}
            map.put("school","SWPU");
            return SUCCESS;
        }
    }   

7.5. ModelAttribute

  • 在方法定义上使用 @ModelAttribute 注解
    • Spring MVC在调用目标处理方法前,会先调用在方法上标注了 @ModelAttribute 的方法。
  • 在方法的入参前使用 @ModelAttribute 注解
    • Spring MVC 会使用 value 属性值在 implicitModel 中查找对应的对象,若存在则会直接传入到目标方法的入参中。
    • Spring MVC 会以value 为 key,POJO类型的对象为 value ,存入到 request 中
  • @ModelAttribute修饰的方法

    • 运行流程:
      • i. 执行@ModelAttribute注解修饰的方法:从数据库中取出对象,把对象放入Map,键:user
      • ii. SpringMVC从Map中取出User对象,并把表单的请求参数赋给该User对象的对应属性
      • iii. SpringMVC把上述对象传入目标方法的参数。
    • 注意:在@ModelAttribute修饰的方法中,放入到Map时的键需要和目标方法入参类型的第一个字母小写的字符串一致。
    • 方法代码

          @ModelAttribute
          public void getUser(@RequestParam(value = "id",required = false)Integer id,Map<String,Object> map){
              if (id!=null){
                  //模拟从数据库中获取对象
                  User user = new User(1,"Tom","123","[email protected]",20);
                  System.out.println("从数据库中获取对象 "+user);
      
                  map.put("user",user);
              }
          }
    • 处理方法代码

          @RequestMapping("/testModelAttribute")
          public String testModelAttribute(User user){
              System.out.println("修改 :"+user);
              return SUCCESS;
          }
  • @ModelAttribute修饰的入参
    此时将 @ModelAttribute 修饰的方法中map所放入的key改为 abc,那在入参中用@ModelAttribute("abc")User user才能接收到。

    • 方法代码

          @ModelAttribute
          public void getUser(@RequestParam(value = "id",required = false)Integer id,Map<String,Object> map){
              if (id!=null){
      
                  User user = new User(1,"Tom","123","[email protected]",20);
                  System.out.println("从数据库中获取对象 "+user);
                  //key修改为abc
                  map.put("abc",user);
              }
          }
    • 处理方法代码

          @RequestMapping("/testModelAttribute")
          public String testModelAttribute(@ModelAttribute("abc")User user){
              System.out.println("修改 :"+user);
              return SUCCESS;
          }

8. 视图和视图解析器

  • 请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView
    对象
    ,它包含了逻辑名和模型对象的视图。
  • Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP
    ,也可能是Excel、JFreeChart 等各种表现形式的视图。
  • 对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦。

8.1. 视图

  • 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户。

  • 为了实现视图模型和具体实现技术的解耦,Spring 在org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口:

        public interface View {
    
          String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus";
    
          String PATH_VARIABLES = View.class.getName() + ".pathVariables";
    
          String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType";
    
          String getContentType();
    
          void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception;
    
        }
  • 视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们 不会有线程安全的问题。

8.2. 视图解析器

  • SpringMVC 为逻辑视图名的解析提供了不同的策略,可以在 Spring WEB 上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。

  • 视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象。所有的视图解析器都必须实现 ViewResolver 接口:

        package org.springframework.web.servlet;
    
        import java.util.Locale;
    
        public interface ViewResolver {
            View resolveViewName(String viewName, Locale locale) throws Exception;
        }
  • 可以用一种视图解析器或混用多种视图解析器。

  • 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。

  • Spring MVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解 析,直到解析成功并返回视图对象,否则将抛出 ServletException 异 常。

8.2.1. InternalResourceViewResolver

  • JSP 是最常见的视图技术,可以使用 InternalResourceViewResolver 作为视图解析器:

        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <property name="prefix" value="/WEB-INF/view/"/>
            <property name="suffix" value=".jsp"/>
        </bean>
  • 若项目中使用了 JSTL,则 SpringMVC 会自动把视图由 InternalResourceView 转为 JstlView

  • 若使用 JSTL 的 fmt 标签则需要在 SpringMVC 的配置文件中配置国际化资源文件

    <!--配置国际化资源文件-->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename" value="i18n"/>
    </bean>
  • 若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

        <!--配置直接转发的页面-->
        <!--可以直接响应转发的页面,不需经过handler的方法-->
        <mvc:view-controller path="/success" view-name="success"/>
        <!--通常都需要配置mvc:annotation-driven标签-->
        <mvc:annotation-driven/>
    • 但同时会导致以前的访问出现404,此时配置mvc:annotation-driven标签
      <!--通常都需要配置mvc:annotation-driven标签-->
      <mvc:annotation-driven/>

8.3. 自定义视图

8.3.1. 例子

  • 自定义视图
    @Component(value = "helloView")
    public class HelloView implements View{
        @Override
        public String getContentType() {
            return "test/html";
        }

        @Override
        public void render(Map<String, ?> map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
            httpServletResponse.getWriter().print("Hello View,Time: "+ new Date());
        }
    }
  • 配置 BeanNameViewResolver 视图解析器:使用视图的名字来解析视图
    <!--通过order属性来定义视图解析器的优先级,order值越小优先级越高-->
    <bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
        <property name="order" value="100"/>
    </bean>
  • BeanNameViewResolver源代码
public class BeanNameViewResolver extends WebApplicationObjectSupport implements ViewResolver, Ordered {

    private int order = Integer.MAX_VALUE;  // default: same as non-Ordered

    public void setOrder(int order) {
        this.order = order;
    }

    @Override
    public int getOrder() {
        return this.order;
    }


    @Override
    public View resolveViewName(String viewName, Locale locale) throws BeansException {
        ApplicationContext context = getApplicationContext();
        if (!context.containsBean(viewName)) {
            if (logger.isDebugEnabled()) {
                logger.debug("No matching bean found for view name '" + viewName + "'");
            }

            return null;
        }
        if (!context.isTypeMatch(viewName, View.class)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Found matching bean for view name '" + viewName +
                        "' - to be ignored since it does not implement View");
            }
            return null;
        }
        return context.getBean(viewName, View.class);
    }

}
  • 可以看到return context.getBean(viewName, View.class),当没有发生异常时,BeanNameViewResolver 会通过viewName从容器中得到bean,所以我们需要将自定义的视图放入容器中。
  • 此时我们设定的BeanNameViewResolver 的order为100,InternalResourceViewResolver的可以通过源代码知道,其order是Integer.MAX_VALUE。

  • 控制器定义处理方法

    @RequestMapping("/testView")
    public String testView(){
        System.out.println("testView");
        return  "helloView";
    }

8.3.2. 自定义Excel视图

  • 若希望使用 Excel 展示数据列表,仅需要扩展 Spring MVC 提供的 AbstractExcel ViewAbstractJExcel View 即可。实现 buildExcelDocument() 方法,在方法中使用模型数据对象构建 Excel
    文档就可以了。

  • AbstractExcelView 基于 POI API,而 AbstractJExcelView 是基于 JExcelAPI 的。

  • 视图对象需要配置 IOC 容器中的一个 Bean,使用BeanNameViewResolver 作为视图解析器即可。

  • 若希望直接在浏览器中直接下载 Excel 文档,则可以设置响应头 Content-Disposition 的值为attachment;filename=xxx.xls


9. 重定向与转发

  • 一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理。

  • 如果返回的字符串中带 forward:redirect: 前缀时,Spring MVC 会将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理。

    • redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
    • forward:success.jsp:会完成一个到 success.jsp 的转发操作
  • 在 InternalResourceViewResolver 所继承的父类 UrlBasedViewResolver 中定义了createView方法会对返回的字符串进行处理。

    • 源代码如下
    protected View createView(String viewName, Locale locale) throws Exception {
        // If this resolver is not supposed to handle the given view,
        // return null to pass on to the next resolver in the chain.
        if (!canHandle(viewName, locale)) {
            return null;
        }
        // Check for special "redirect:" prefix.
        if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
            String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
            RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
            view.setHosts(getRedirectHosts());
            return applyLifecycleMethods(viewName, view);
        }
        // Check for special "forward:" prefix.
        if (viewName.startsWith(FORWARD_URL_PREFIX)) {
            String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
            return new InternalResourceView(forwardUrl);
        }
        // Else fall back to superclass implementation: calling loadView.
        return super.createView(viewName, locale);
    }
  • 处理方法代码
    @RequestMapping("/testRedirect")
    public String testRedirect(){
        System.out.println("testRedirect");
        return "redirect:/index.jsp";
    }

猜你喜欢

转载自blog.csdn.net/qq_37138933/article/details/79252085