Spring MVC(一)
Spring MVC概括
-
什么是MVC
-
MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。
-
MVC主要作用是降低了视图与业务逻辑间的双向偶合。
-
MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异
Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或者JavaBean组件(包括数据和行为),不过现在一般分离开来:Value Object(数据Dao) 和服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。
View(视图):负责进行模型的展示,一般就是我们见到的用户界面,用户想看到的东西。
Conttroller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责 展示、也就是说控制器做了个调度员的工作。
最典型的MVC就是JSP+Servlet+JavaBean
-
-
Model1
在Web开发早期通常采用Model1模式进行开发。
在Model1模式下,整个Web应用几乎全部用JSP页面组成,只用少量的JavaBean来处理数据库连接、访问等操作
这个模式下JSP即使控制层(Controller)又是视图层(View)。这明显不符合Java的单一职责原则。比如控制逻辑和表现逻辑混杂在一起,导致代码重用率极低;再比如前端和后端相互依赖,难以进行测试维护并且开发效率极低。
Model1优点:架构简单,适合小型项目开发;
Model1缺点:JSP职责不单一,,职责过重,不便于维护
-
Model2
Model2就是上面所述的Java Bean+JSP+Servlet这种开发模式,这就是早期的JavaWeb MVC开发模式。
- Model:系统涉及的数据,也就是dao与bean
- View:展示模型中的数据,只是用来展示
- controller:处理用户请求发送给Model,然后Model返回数据的处理结果给JSP并展示给用户
职责分析:
Controller:控制器
- 取得表单数据
- 调用业务逻辑
- 转向指定的页面
Model:模型
- 业务逻辑
- 保存数据的状态
View:视图
- 显示页面
Model2模式下还存在着很多问题,Model2的抽象和封装程度还远远不够,使用Model2进行开发时不可避免地重复造轮子,这就大大降低了程序的可维护性和复用性。
于是,很多JavaWeb开发相关的MVC框架应运而生,比如Stuts2,但是Struts2比较笨重。
-
Spring MVC时代
随着Spring轻量级开发框架1的流行,Spring生态圈出现了Spring MVC框架,Spring MVC框架是当前最优秀的MVC框架。相比于Struts2,Spring MVC使用更加啊简单和方便,开发效率更高,并且Spring MVC运行速度更快。
MVC是一种设计模式,Spring MVC是一款很优秀的MVC框架。Spring MVC可以帮我们更简洁Web层的开发,并且它天生与Spring框架集成。Spring MVC下我们一般把后端项目分为Service层(处理业务)、dao层(数据库操作)、Entity层(实体类)、Controller层(控制层)
Spring MVC工作原理
Spring MVC的原理如下图所示:
- 流程说明:
- 客户端(浏览器)发送请求,直接请求到
DispatcherServlet
。 DispatcherServlet
根据请求信息调用HandlerMapper
,解析请求对应的Handler
。- 解析到对应的
Handler
(也就是Controller控制器)后,开始由HandlerAdapter
适配器处理。 HandlerAdapter
会根据Handler
来调用真正的处理器来处理请求,并处理相应的业务逻辑。- 处理器处理完业务后,会返回一个
ModelAndView
对象,Model
是返回的数据对象,View
是逻辑上的View。 ViewResolver
会根据逻辑View
查找实际的View
。DispaterServlet
把返回的Model
传给View
(视图渲染)。- 把
View
返回给请求者(浏览器)。
- 客户端(浏览器)发送请求,直接请求到
第一个Spring MVC程序
使用配置实现
-
创建并部署项目springmvc-02-hello;导入依赖
-
配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--注册dispatchServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联一个1spring的配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> <!--启动级别 1--> <load-on-startup>1</load-on-startup> </servlet> <!--/-匹配所有请求:不包括.jsp--> <!--/*-匹配所有请求:包括.jsp--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
-
编写SpringMVC的配置文件:springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--添加处理映射器--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!--添加处理适配器--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!--添加视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"></property> <!--后缀--> <property name="suffix" value=".jsp"></property> </bean> <!--Handler--> <bean id="/hello" class="com.heng.controller.HelloController"></bean> </beans>
-
编写操作业务的Controller控制器,要么实现Controller接口,要么增加注解;需要返回一个ModelAndView,装数据,封视图。
package com.heng.controller; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Author: minster * @Date: 2021/11/10 9:38 */ public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //ModelAndView模型和视图 ModelAndView mv = new ModelAndView(); //封装对象,放在ModelAndView中。Model mv.addObject("msg","HelloSpringMVC!"); //封装要跳转的视图,放在ModelAndView中 mv.setViewName("hello"); return mv; } }
-
在spring中注册上面的类
</bean> <!--Handler--> <bean id="/hello" class="com.heng.controller.HelloController"></bean>
-
编写jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>HelloSpringMVC</title> </head> <body> ${msg} </body> </html>
-
测试
使用注解实现
-
新建一个Moudle,springmvc-03-annotation。添加web支持,导入依赖
-
由于Maven可能存在资源过滤问题,我们将其配置完善
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build>
-
配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--注册servlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--关联springmvc的配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> <!--设置启动顺序--> <load-on-startup>1</load-on-startup> </servlet> <!--所有请求都会被springmvc拦截--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
/ 和 /* 的区别:
< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;即:.jsp 不会进入spring的 DispatcherServlet类 。
< url-pattern > /* </ url-pattern > 会匹配 *.jsp,会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。
-
添加Spring MVC的配置文件
<?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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--自动扫描包,让指定包下的注解生效,由IOC统一管理--> <context:component-scan base-package="com.heng.controller"></context:component-scan> <!--让SpringMVC不处理静态资源--> <mvc:default-servlet-handler></mvc:default-servlet-handler> <!--支持mvc注解驱动--> <mvc:annotation-driven></mvc:annotation-driven> <!--视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!--前缀--> <property name="prefix" value="/WEB-INF/jsp/"></property> <!--后缀--> <property name="suffix" value=".jsp"></property> </bean> </beans>
**
<mvc:annotation-driven></mvc:annotation-driven>
**作用:在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例
这两个实例分别在类级别和方法级别处理。而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-
创建Controller
package com.heng.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; /** * @Author: minster * @Date: 2021/11/10 15:16 */ @Controller @RequestMapping("/HelloController") public class HelloController { //真实访问地址 : 项目名/HelloController/hello @RequestMapping("/hello") public String hello(Model model){ model.addAttribute("msg","helloSpringMVCAnnotation"); return "hello"; } }
- @Controller是为了让Spring IOC容器初始化时自动扫描到;
- @RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/HelloController/hello;
- 方法中声明Model类型的参数是为了把Action中的数据带到视图中;
- 方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp。
-
创建视图层
在WEB-INF/ jsp目录中创建hello.jsp , 视图可以直接取出并展示从Controller带回的信息;
可以通过EL表示取出Model中存放的值,或者对象;
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello</title> </head> <body> ${msg} </body> </html>
-
测试运行
小结
使用springMVC必须配置的三大件:
处理器映射器、处理器适配器、视图解析器
通常,我们只需要手动配置视图解析器,而处理器映射器和处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置
@Controller与@RequestMappping
-
控制器Controller
- 控制器复杂提供访问应用程序的行为1,通常通过接口定义或注解定义两种方式实现。
- 控制器负责解析用户的请求并将其转换为一个模型。
- 在Spring MVC中一个控制器类可以包含多个方法
- 在Spring MVC中,对于Controller的配置方式有很多种
实现Controller接口来配置Controller
Controller接口
package org.springframework.web.servlet.mvc; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; import org.springframework.web.servlet.ModelAndView; @FunctionalInterface public interface Controller { @Nullable ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception; }
观察上面代码我们可以知道,当我们使用Controller接口来配置Controller时,我们只需要实现一个返回ModelAndView的方法即可。
package com.heng.controller; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Author: minster * @Date: 2021/11/10 9:38 */ public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //ModelAndView模型和视图 ModelAndView mv = new ModelAndView(); //封装对象,放在ModelAndView中。Model mv.addObject("msg","HelloSpringMVC!"); //封装要跳转的视图,放在ModelAndView中 mv.setViewName("hello"); return mv; } }
使用该方法还需要去Spring MVC的配置文件springmvc-servlet.xml中注册一个Bean
<!--Handler--> <bean id="/hello" class="com.heng.controller.HelloController"></bean>
使用@Controller注解来配置Controller
@Controller注解类型用于声明Spring类的实例是一个控制器(在讲IOC时还提到了另外3个注解);
Spring可以使用扫描机制来找到应用程序中所有基于注解的控制器类,为了保证Spring能找到你的控制器,需要在配置文件中声明组件扫描
<!-- 自动扫描指定的包,下面所有注解类交给IOC容器管理 --> <context:component-scan base-package="com.kuang.controller"/>
使用@Controller注解
package com.heng.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; /** * @Author: minster * @Date: 2021/11/10 15:16 */ @Controller //映射访问路径 @RequestMapping("/HelloController") public class HelloController { //映射访问路径,真实访问路径为localhost:8080/HelloController/hello @RequestMapping("/hello") public String hello(Model model){ //Spring MVC会自动实例化一个Model对象用于向视图中传值 model.addAttribute("msg","helloSpringMVCAnnotation"); return "hello"; } }
测试结果
-
@RequestMapping
从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
@RequestMapping可以在标注一个方法或者一个类
- @RequestMapping标识一个类:设置映射请求的请求路径的初始信息
- @RequestMapping标识一个方法:设置映射请求请求路径的具体信息
@Controller @RequestMapping("/HelloController") public class HelloController { //此时请求映射所映射的请求的请求路径为:/HelloController/hello @RequestMapping("/hello") public String hello(Model model){ model.addAttribute("msg","helloSpringMVCAnnotation"); return "hello"; } }
RestFul风格
REST:Representational State Transfer,表现层资源状态转移
概念
RestFul就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更安全,更易于实现缓存等机制。
-
资源
资源是一种看待服务器的方式,即,将服务器看作是由很多离散的资源组成。每个资源是服务器上一个可命名的抽象概念。因为资源是一个抽象的概念,所以它不仅仅能代表服务器文件系统中的一个文件、数据库中的一张表等等具体的东西,可以将资源设计的要多抽象有多抽象,只要想象力允许而且客户端应用开发者能够理解。与面向对象设计类似,资源是以名词为核心来组织的,首先关注的是名词。一个资源可以由一个或多个URI来标识。URI既是资源的名称,也是资源在Web上的地址。对某个资源感兴趣的客户端应用,可以通过资源的URI与其进行交互。
互联网所有的事物都可以被抽象为资源
-
状态转移
状态转移说的是:在客户端和服务器端之间转移(transfer)代表资源状态的表述。通过转移和操作资源的表述,来间接实现操作资源的目的。
RestFul的实现
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。
操作 | 传统方式 | REST风格 |
---|---|---|
查询操作 | getUserById?id=1 | user/1–>get请求方式 |
保存操作 | saveUser | user–>post请求方式 |
删除操作 | deleteUser?id=1 | user/1–>delete请求方式 |
更新操作 | updateUser | user–>put请求方式 |
测试案例
-
创建Controller
package com.heng.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /** * @Author: minster * @Date: 2021/11/11 9:15 */ @Controller public class RestFulController { @RequestMapping("/restFul/{p1}/{p2}") public String restFul(@PathVariable int p1,@PathVariable int p2, Model model){ int res = p1+p2; model.addAttribute("msg","结果为 "+res); return "test"; } }
-
测试
-
注意:
通过路径变量的类型可以约束访问参数,如果类型不一样,则访问不到对应的请求方法,如这里访问是的路径是/restFul/1/a,则路径与方法不匹配,而不会是参数转换失败。
使用method属性可以指定请求类型
@RequestMapping中的method属性可以用于约束请求的类型,可以收窄请求范围。
把上面的restFul方法改为
@Controller
public class RestFulController {
@RequestMapping(value = "/restFul/{p1}/{p2}",method = RequestMethod.POST)
public String restFul(@PathVariable int p1,@PathVariable int p2, Model model){
int res = p1+p2;
model.addAttribute("msg","结果为 "+res);
return "test";
}
}
我们再去浏览器请求
可以发现网页报了405的错误;因为我们浏览器地址栏进行访问默认是Get请求!!!!
如果把POST改为GET就可以正常访问了!
@Controller
public class RestFulController {
@RequestMapping(value = "/restFul/{p1}/{p2}",method = RequestMethod.GET)
public String restFul(@PathVariable int p1,@PathVariable int p2, Model model){
int res = p1+p2;
model.addAttribute("msg","结果为 "+res);
return "test";
}
}
小结:
Spring MVC 的 @RequestMapping 注解能够处理 HTTP 请求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH。
所有的地址栏请求默认都会是 HTTP GET 类型的。
方法级别的注解变体有如下几个:组合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一个组合注解,平时使用的会比较多!
它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一个快捷方式。
数据处理及跳转
数据处理
处理提交的数据
-
提交的域名城和处理方法的参数名一致
提交数据:http://localhost:8080/commit?name=minster
处理方法:
@Controller public class TestController1 { @RequestMapping("/commit") public String commitName(String name, Model model){ model.addAttribute("msg","Name = "+name); System.out.println(name); return "test"; } }
后台输出minster
前端显示页面
-
提交的域名称和处理方法的参数名不一致
提交数据:http://localhost:8080/commit?username=minster
处理方法:
@Controller public class TestController1 { @RequestMapping("/commit") public String commitName(@RequestParam("username") String name, Model model){ model.addAttribute("msg","Name = "+name); System.out.println(name); return "test"; } }
后台输出minster
前端显示:
如果此时我们提交的数据为 name=minster,服务器会报错
因为我们使用@RequestParam会约束请求提交的参数名!
-
提交一个对象
要求提交的表单域和对象的属性名一致 , 参数使用对象即可
创建实体类User
package com.heng.pojo; /** * @Author: minster * @Date: 2021/11/11 12:31 */ public class User { private int id; private String name; private int age; }
提交数据:http://localhost:8080/user?id=1&name=minster&age=21
处理方法:
@RequestMapping("/user") public String commitUser(User user){ System.out.println(user); return "test"; }
后台成功输出User{id=1, name=‘minster’, age=21}
说明:如果使用对象的话,前端传递的参数名和对象名必须一致,否则就是null。
数据显示到前端
-
ModelAndView
public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //返回一个模型视图对象 ModelAndView mv = new ModelAndView(); mv.addObject("msg","ControllerTest1"); mv.setViewName("test"); return mv; } }
-
ModelMap
@RequestMapping("/commit") public String commitName(@RequestParam("username") String name, ModelMap map){ map.addAttribute("msg","Name = "+name); System.out.println(name); return "test"; }
-
Model
@RequestMapping("/ct2/hello") public String hello(@RequestParam("username") String name, Model model){ //封装要显示到视图中的数据 //相当于req.setAttribute("name",name); model.addAttribute("msg",name); System.out.println(name); return "test"; }
对比:
Model 只有寥寥几个方法只适合用于储存数据,简化了新手对于Model对象的操作和理解;
ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图,进行控制展示层的跳转。
页面跳转
-
**转发:**由服务器端进行的页面跳转;
-
**重定向(Redirect):**由浏览器端进行的页面跳转;
重定向是指当浏览器请求一个URL时,服务器返回一个重定向指令,告诉浏览器地址已经变了,麻烦使用新的URL再重新发送新请求。
ModelAndView
设置ModelAndView对象,根据View的名称和视图解析器可以跳转到指定的页面
页面 = {视图解析器前缀} + ViewName + {视图解析器后缀}
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
对应的Controller类
@Controller
@RequestMapping("/HelloController")
public class HelloController {
@RequestMapping("/hello")
public String hello(Model model){
model.addAttribute("msg","helloSpringMVCAnnotation");
return "hello";
}
}
访问的url为 localhost:8080/HelloController/hello
ServletAPI
通过设置ServletAPI , 不需要视图解析器 .
1、通过HttpServletResponse进行输出
2、通过HttpServletResponse实现重定向
3、通过HttpServletResponse实现转发
@Controller
public class ResultGo {
@RequestMapping("/result/t1")
public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
rsp.getWriter().println("Hello,Spring BY servlet API");
}
@RequestMapping("/result/t2")
public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
//重定向
rsp.sendRedirect("/index.jsp");
}
@RequestMapping("/result/t3")
public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception {
//转发
req.setAttribute("msg","/result/t3");
req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp);
}
}
SpringMVC
通过SpringMVC来实现转发和重定向 - 无需视图解析器;
测试前,需要将视图解析器注释掉
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//转发
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//转发二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
通过SpringMVC来实现转发和重定向 - 有视图解析器;
重定向 , 不需要视图解析器 , 本质就是重新请求一个新地方嘛 , 所以注意路径问题.
可以重定向到另外一个请求实现 .
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//转发
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; //hello.do为另一个请求/
}
}
乱码问题
案例演示
-
我们在首页编写一个提交的表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>乱码问题</title> </head> <body> <form action="/commitForm" method="post"> <input type="text" name="name"> <input type="submit"> </form> </body> </html>
-
后台编写对应的处理方法
@RequestMapping("/commitForm") public String commitForm(Model model , String name){ model.addAttribute("msg",name); return "test"; }
-
测试
输出结果,发现乱码
以前乱码问题通过过滤器解决 , 而SpringMVC给我们提供了一个过滤器 , 可以在web.xml中配置 .
修改了xml文件需要重启服务器!
<filter> <filter-name>encoding</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> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
运行
问题解决!
如果我们使用上述过滤器还不能解决乱码问题的话,我们可以自定义一个强大的过滤器!(网上一个大佬写的过滤器,基本所有乱码问题都能解决!)
package com.heng.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
* 解决get和post请求 全部乱码的过滤器
*/
@SuppressWarnings({"all"})
public class GenericEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//处理response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) response;
myResponse.setContentType("text/html;charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(myrequest, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
@SuppressWarnings({"all"})
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是否编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
// 对需要增强方法 进行覆盖
@Override
public Map getParameterMap() {
// 先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
// 处理post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) { // 确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
// 处理get乱码
values[i] = new String(values[i]
.getBytes("ISO-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
//取一个值
@Override
public String getParameter(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null) {
return null;
}
return values[0]; // 取回参数的第一个值
}
//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
然后再web.xml中配置一下即可!