ToB企服应用市场:ToB评测及商务社交产业平台

标题: SpringMVC-04-结果跳转及数据处置惩罚 [打印本页]

作者: 嚴華    时间: 2024-7-18 01:38
标题: SpringMVC-04-结果跳转及数据处置惩罚
1、结果跳转

SpringMVC中有两种实现 Handler 的方式:接口实现 和 注解实现,
两种方式对请求结果的处置惩罚各有不同。
1.1、接口Handler处置惩罚结果
  1. public class ControllerTest implements Controller {
  2.    
  3.     @Override
  4.     public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
  5.         ModelAndView mv = new ModelAndView();
  6.         mv.addObject("msg", "ControllerTest");
  7.         mv.setViewName("/test");
  8.         return mv;
  9.     }
  10. }
复制代码
接口Handler使用ModelAndView对象处置惩罚结果
ModelAndView是SpringMVC中的一种 中间数据对象,
封装了 Model层处置惩罚后的结果数据 和 将要跳转视图的逻辑视图名,
走视图解析器,逻辑视图名拼接前后缀。
1.2、注解Handler处置惩罚结果
  1. @Controller
  2. @RequestMapping("/h1")
  3. public class HandlerMethodTest {
  4.     // 返回值 void 参数有 resp , 结果:不走视图解析器,响应自然返回,由 resp 控制
  5.     @RequestMapping("/t1")
  6.     public void test1(HttpServletResponse resp) {
  7.         System.out.println("方法参数为:resp");
  8.     }
  9.     // 返回值 void 参数无 resp , 结果:走视图解析器,逻辑视图名 默认为 对应的RequestMappingInfo的路径
  10.     @RequestMapping("/t2")
  11.     public void test2(HttpServletRequest req, Model model) throws IOException {
  12.         model.addAttribute("msg", "test2");
  13.         System.out.println("方法参数为:req + model");
  14.     }
  15.     // 返回值 String 无论参数 ,
  16.     // 结果1(没被 @ResponseBody 标注):统一走视图解析器,逻辑视图名 为返回的String值
  17.     // 结果2(被 @ResponseBody 标注):不走视图解析器,返回的String值被当作响应体返回
  18.     @RequestMapping("/t3")
  19.     @ResponseBody
  20.     public String test3(HttpServletRequest req, HttpServletResponse resp, Model model) throws Exception {
  21.         model.addAttribute("msg", "test3");
  22.         return "test";
  23.     }
  24. }
复制代码
注解Handler,即HandlerMethod,
其相应的Handler适配器 根据其返回值和方法参数的不同,有不同的实行计谋:
@ResponseBody 作用:
  改变 HandlerMethod 的返回值意义,把其看成响应体而不是逻辑视图名直接返回给客户端浏览器,一般标注在返回值为String的 HandlerMethod 上,因为返回的响应体为空值没有意义。
1.3、forward与redirect
  1. @Controller
  2. @RequestMapping("/r1")
  3. public class ResultController {
  4.     @RequestMapping("/t1")
  5.     public String test(Model model) {
  6.         model.addAttribute("msg", "Result1");
  7.         return "test";
  8.     }
  9.     @RequestMapping("/t2")
  10.     public String test2(Model model) {
  11.         // 转发:forward 视图解析器的特殊前缀,对后面的路径执行转发操作,不做逻辑视图名那样的前后缀拼接
  12.         model.addAttribute("msg", "Result2");
  13.         return "forward:/WEB-INF/jsp/test.jsp";
  14.     }
  15.     @RequestMapping("/t3")
  16.     public String test3(Model model) {
  17.         // 重定向:redirect 视图解析器的特殊前缀,对后面的路径执行重定向操作,不做逻辑视图名那样的前后缀拼接
  18.         model.addAttribute("msg", "Result3");
  19.         return "redirect:/r1/t2";
  20.     }
  21. }
复制代码
forward:和redirect:为 视图解析器的特殊前缀,
对后面的路径实行转发或者重定向操纵,不做逻辑视图名那样的前后缀拼接。

官方文档翻译:
指定转发或重定向URL的特殊视图名称的前缀(通常在表单提交和处置惩罚后发送给控制器)。
此类视图名称将不会以配置的默认方式解析,而是被视为特殊的快捷方式。

2、参数数据绑定

在SpringMVC 使用注解处置惩罚请求的方式中,框架会对 HandlerMethod 的方法参数 进行数据绑定,以便于更简便的处置惩罚请求。
数据绑定的方式分为三种:传统数据绑定、路径变量绑定 和 特定参数绑定
三种绑定方式对于不同的方法参数皆有不同的处置惩罚。
留意:后端获取前端数据,都是把它当成String类型获取,再将其解析转换成相应的类型
2.1、传统数据绑定

获取 请求参数 为绑定值:request.getParameter("参数名")
2.2、路径变量绑定

路径变量,即 URI模板变量,是一种简化URL配置的方式,它答应你使用占位符来表示路径动态变革的部分。
编写方式:/{占位符1}/{占位符2}……
例子:/users/{userId}/posts/{postId},userId和postId即是路径变量,变量值由前端具体的URL格式化得来。
路径变量 可以被绑定到 HandlerMethod 的方法参数上,这是一种将前端参数写入URL路径的方式,
其只用URL来表示具体的资源位置,符合Rest风格。
获取 路径变量 为绑定值:格式化具体的URL得来
2.3、特定参数绑定

HandlerMethod 的方法参数中有一些特定的类型,比如:HttpServletRequest、HttpServletResponse、Model、ModelMap……
它们做数据绑定时,由框架传入特定的对象
这些类型基本上都是框架内部组织的一部分:
HttpServletRequest 代表 请求、
HttpServletResponse 代表 响应、
Model、ModelMap 代表 中间数据容器
获取 框架内部对象 为绑定值:由框架传入
3、中间数据对象

三者对比
就对于新手而言简单来说,使用区别就是:
  1. Model 只是标准接口,只有寥寥几个方法用于储存数据,简化了新手对于Model对象的操作和理解;
  2. ModelMap 继承了 LinkedMap ,除了实现了自身的一些方法,同样的继承 LinkedMap 的方法和特性;
  3. ModelAndView 可以在储存数据的同时,可以进行设置返回的逻辑视图名,控制视图层的跳转。
复制代码
当然,以后开辟考虑的更多的是性能和优化,就不能单单仅限于此的了解。
三者关系

4、乱码问题

测试步骤:
Post请求中文参数乱码

原因分析:
总所周知,Post参数数据存储在请求体里面,以页面编码解码,变成字节省形式存储,以二进制流的形式发送到的服务器。
服务器收到数据后,以默认编码进行编码。
这里,我的服务器用的是Tomcat9,默认编码为 ISO-8859-1 ,页面编码用的是 UTF-8
前后端编码不一致,导致乱码。

解决:
给服务器设置解析请求的字符集即可,request.setCharacterEncoding("UTF-8");
在项目中,可以写一个过滤器来操纵,这里我们可以使用SpringMVC提供的字符集过滤器,在web.xml中配置
  1.     <filter>
  2.         <filter-name>Encoding</filter-name>
  3.         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  4.         <init-param>
  5.             <param-name>encoding</param-name>
  6.             <param-value>utf-8</param-value>
  7.         </init-param>
  8.     </filter>
  9.     <filter-mapping>
  10.         <filter-name>Encoding</filter-name>
  11.         <servlet-name>DispatcherServlet</servlet-name>
  12.     </filter-mapping>
复制代码
当然,我们也可以自界说过滤器,这里提供网上一位大神的写的
  1. package com.kuang.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletRequestWrapper;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.io.UnsupportedEncodingException;
  8. import java.util.Map;
  9. /**
  10. * 解决get和post请求 全部乱码的过滤器
  11. */
  12. public class GenericEncodingFilter implements Filter {
  13.     @Override
  14.     public void destroy() {
  15.     }
  16.     @Override
  17.     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
  18.         //处理response的字符编码
  19.         HttpServletResponse myResponse=(HttpServletResponse) response;
  20.         myResponse.setContentType("text/html;charset=UTF-8");
  21.         // 转型为与协议相关对象
  22.         HttpServletRequest httpServletRequest = (HttpServletRequest) request;
  23.         // 对request包装增强
  24.         HttpServletRequest myrequest = new MyRequest(httpServletRequest);
  25.         chain.doFilter(myrequest, response);
  26.     }
  27.     @Override
  28.     public void init(FilterConfig filterConfig) throws ServletException {
  29.     }
  30. }
  31. //自定义request对象,HttpServletRequest的包装类
  32. class MyRequest extends HttpServletRequestWrapper {
  33.     private HttpServletRequest request;
  34.     //是否编码的标记
  35.     private boolean hasEncode;
  36.     //定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
  37.     public MyRequest(HttpServletRequest request) {
  38.         super(request);// super必须写
  39.         this.request = request;
  40.     }
  41.     // 对需要增强方法 进行覆盖
  42.     @Override
  43.     public Map getParameterMap() {
  44.         // 先获得请求方式
  45.         String method = request.getMethod();
  46.         if (method.equalsIgnoreCase("post")) {
  47.             // post请求
  48.             try {
  49.                 // 处理post乱码
  50.                 request.setCharacterEncoding("utf-8");
  51.                 return request.getParameterMap();
  52.             } catch (UnsupportedEncodingException e) {
  53.                 e.printStackTrace();
  54.             }
  55.         } else if (method.equalsIgnoreCase("get")) {
  56.             // get请求
  57.             Map<String, String[]> parameterMap = request.getParameterMap();
  58.             if (!hasEncode) { // 确保get手动编码逻辑只运行一次
  59.                 for (String parameterName : parameterMap.keySet()) {
  60.                     String[] values = parameterMap.get(parameterName);
  61.                     if (values != null) {
  62.                         for (int i = 0; i < values.length; i++) {
  63.                             try {
  64.                                 // 处理get乱码
  65.                                 values[i] = new String(values[i]
  66.                                         .getBytes("ISO-8859-1"), "utf-8");
  67.                             } catch (UnsupportedEncodingException e) {
  68.                                 e.printStackTrace();
  69.                             }
  70.                         }
  71.                     }
  72.                 }
  73.                 hasEncode = true;
  74.             }
  75.             return parameterMap;
  76.         }
  77.         return super.getParameterMap();
  78.     }
  79.     //取一个值
  80.     @Override
  81.     public String getParameter(String name) {
  82.         Map<String, String[]> parameterMap = getParameterMap();
  83.         String[] values = parameterMap.get(name);
  84.         if (values == null) {
  85.             return null;
  86.         }
  87.         return values[0]; // 取回参数的第一个值
  88.     }
  89.     //取所有值
  90.     @Override
  91.     public String[] getParameterValues(String name) {
  92.         Map<String, String[]> parameterMap = getParameterMap();
  93.         String[] values = parameterMap.get(name);
  94.         return values;
  95.     }
  96. }
复制代码
Get请求无乱码分析

在上面的测试中可以看到,在Post请求乱码的情况下,Get请求可以或许正常体现中笔墨符,这是什么原因呢?
Get请求的参数写在URL中,一般来说,URL只能使用英笔墨母、阿拉伯数字和某些标点符号,不能使用其他笔墨和符号。
这是因为网络标准RFC 1738做了硬性规定:
  1. "...Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL."
  2. "只有字母和数字[0-9a-zA-Z]、一些特殊符号"$-_.+!*'(),"[不包括双引号]、以及某些保留字,才可以不经过编码直接用于URL。"
复制代码
这意味着,如果URL中有汉字,就必须编码后使用。但是麻烦的是,RFC 1738没有规定具体的编码方法,而是交给应用步伐(浏览器)本身决定。这导致"URL编码"成为了一个杂乱的领域。
想深入的可以去看看 关于URL编码 这篇文章,初学者只必要知道现在大部分情况下,浏览器都使用 UTF-8 作为URL编码。
于是,就上面的测试而言,
http://localhost:8080/spring04/e/t?name=斗破苍穹
经过 UTF-8 编码转换,得到
http://localhost:8080/spring04/e/t?name=%E6%96%97%E7%A0%B4%E8%8B%8D%E7%A9%B9
然后,服务器接收到请求,用指定解析URL的编码对其进行解码,得到参数值
Tomcat9 解析URL的默认编码为 UTF-8,具体的值可以在Tomcat的 server.xml 中进行配置
即,Connector标签中的 URIEncoding 属性
[code][/code]乱码问题,必要平时多留意,在尽可能能设置编码的地方,都设置为统一编码 UTF-8!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4