1.结果跳转方式

ModelAndView

设置ModelAndView对象 , 根据view的名称 , 和视图解析器跳到指定的页面 .

页面 : {视图解析器前缀} + viewName +{视图解析器后缀}

  1. <!-- 视图解析器 -->
  2. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
  3. id="internalResourceViewResolver">
  4. <!-- 前缀 -->
  5. <property name="prefix" value="/WEB-INF/jsp/" />
  6. <!-- 后缀 -->
  7. <property name="suffix" value=".jsp" />
  8. </bean>

对应的controller类

  1. public class ControllerTest1 implements Controller {
  2. public ModelAndView handleRequest(HttpServletRequest request,
  3. HttpServletResponse response) throws Exception {
  4. //返回一个模型视图对象
  5. ModelAndView mv = new ModelAndView();
  6. mv.addObject("msg","ControllerTest1");
  7. mv.setViewName("test");
  8. return mv;
  9. }
  10. }

重定向是将用户从当前处理请求定向到另一个视图(例如 JSP)或处理请求,以前的请求(request)中存放的信息全部失效,并进入一个新的 request 作用域;
转发是将用户对当前处理的请求转发给另一个视图或处理请求,以前的 request 中存放的信息不会失效。

转发是服务器行为,重定向是客户端行为。

重定向和转发

1)转发过程
客户浏览器发送 http 请求,Web 服务器接受此请求,调用内部的一个方法在容器内部完成请求处理和转发动作,
将目标资源发送给客户;在这里转发的路径必须是同一个 Web 容器下的 URL,其不能转向到其他的 Web 路径上,中间传递的是自己的容器内的 request。

在客户浏览器的地址栏中显示的仍然是其第一次访问的路径,也就是说客户是感觉不到服务器做了转发的。
转发行为是浏览器只做了一次访问请求。

2)重定向过程
客户浏览器发送 http 请求,Web 服务器接受后发送 302 状态码响应及对应新的 location 给客户浏览器,
客户浏览器发现是 302 响应,则自动再发送一个新的 http 请求,请求 URL 是新的 location 地址,服务器根据此请求寻找资源并发送给客户。

在这里 location 可以重定向到任意 URL,既然是浏览器重新发出了请求,那么就没有什么 request 传递的概念了。在客户浏览器的地址栏中显示的是其重定向的路径,客户可以观察到地址的变化。重定向行为是浏览器做了至少两次的访问请求。

重定向与转发的示例代码如下:

  1. package com.yuanzi.controller;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. @Controller
  5. @RequestMapping("/index")
  6. public class IndexController {
  7. @RequestMapping("/login")
  8. public String login() {
  9. //转发到一个请求方法(同一个控制器类可以省略/index/)
  10. return "forward:/index/isLogin";
  11. }
  12. @RequestMapping("/isLogin")
  13. public String isLogin() {
  14. //重定向到一个请求方法
  15. return "redirect:/index/isRegister";
  16. }
  17. @RequestMapping("/isRegister")
  18. public String isRegister() {
  19. //转发到一个视图
  20. return "register";
  21. }
  22. }

image.png


2.数据处理

后端接收参数

1、提交的域名称和处理方法的参数名一致
提交数据 : http://localhost:8080/hello?name=yuanzi
处理方法 :

  1. //localhost: 8080/user/t1 ? name=xxx;
  2. @GetMapping("/t1")
  3. public String test1(String name, Model model){
  4. System.out.println("接收到前端的参数为: " + name);
  5. model.addAttribute("msg", name);
  6. return "test1";
  7. }

后台输出 : yuanzi

2、提交的域名称和处理方法的参数名不一致
提交数据 : http://localhost:8080/hello?username=yuanzi
处理方法 :

  1. //localhost: 8080/user/t1 ? username=xxx;
  2. @GetMapping("/t1")
  3. public String test1(@RequestParam("username") String name, Model model){
  4. //1.接受前端参数
  5. System.out.println("接收到前端的参数为: " + name);
  6. //2.将返回的结果传递给前端
  7. model.addAttribute("msg", name);
  8. //3.视图跳转
  9. return "test1";
  10. }

后台输出 : yuanzi
image.png

3、提交的是一个对象
要求提交的表单域和对象的属性名一致 , 参数使用对象即可
1、实体类

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class User {
  5. private int id;
  6. private String name;
  7. private int age;
  8. }

2、提交数据 : http://localhost:8080/mvc04/user?name=yuanzi&id=1&age=18
3、处理方法 :

  1. @GetMapping("/t2")
  2. public String test2(User user){
  3. System.out.println(user);
  4. return "test1";
  5. }

后台输出 : User { id=1, name=’yuanzi’, age=18}
说明:如果使用对象的话,前端传递的参数名和对象名必须一致,否则就是null。
image.png

数据返回到前端

第一种 : 通过ModelAndView

  1. public class ControllerTest1 implements Controller {
  2. public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
  3. //返回一个模型视图对象
  4. ModelAndView mv = new ModelAndView();
  5. mv.addObject("msg","ControllerTest1");
  6. mv.setViewName("test");
  7. return mv;
  8. }
  9. }

第二种 : 通过ModelMap

  1. ModelMap
  2. @RequestMapping("/hello")
  3. public String hello(@RequestParam("username") String name, ModelMap model){
  4. //封装要显示到视图中的数据
  5. //相当于req.setAttribute("name",name);
  6. model.addAttribute("name",name);
  7. System.out.println(name);
  8. return "hello";
  9. }

第三种 : 通过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与ModelAndView的最大区别:
  • Model只是用来传输数据的,并不会进行业务的寻址。ModelAndView则可以进行业务寻址,即可以设置对应的要请求的静态文件(jsp等)。
  • Model是每次请求可以自动创建的,而ModelAndView是需要自行new的。

Model
  • Model是一个接口,其实现类为ExtendedModelMap,继承了ModelMap类。
public class ExtendedModelMap extends ModelMap implements Model

ModelMap
  • ModelMap对象主要用于传递控制方法处理数据到结果页面,也就是说我们把结果页面上需要的数据放到ModelMap对象中即可。通过以下方法向页面传递参数:
public ModelMap addAttribute(String attributeName, Object attributeValue){...}
public ModelMap addAttribute(Object attributeValue){...}
public ModelMap addAllAttributes(Collection<?> attributeValues) {...}
public ModelMap addAllAttributes(Map<String, ?> attributes){...}

在jsp页面上可以通过el表达式语言$attributeName或者是C标签库下的方法,来获取并展示ModelMap中的数据。

ModelMap本身不能设置页面跳转的url地址别名或者物理跳转地址,那么我们可以通过控制器方法的返回值来设置跳转url地址别名或者物理跳转地址。


乱码问题

测试步骤:
1、我们可以在首页编写一个提交的表单

<form action="/e/t" method="post">
 <input type="text" name="name">
 <input type="submit">
</form>

2、后台编写对应的处理类

@Controller
public class Encoding {
   @RequestMapping("/e/t")
   public String test(Model model,String name){
       model.addAttribute("msg",name); //获取表单提交的值
       return "test"; //跳转到test页面显示输入的值
  }
}

3、输入中文测试,发现乱码

不得不说,乱码问题是在我们开发中十分常见的问题,也是让我们程序猿比较头大的问题!
以前乱码问题通过过滤器解决 , 而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>

但是我们发现 , 有些极端情况下.这个过滤器对get的支持不好

处理方法 :
1、修改tomcat配置文件 :设置编码!

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

2、自定义过滤器

package com.kuang.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请求 全部乱码的过滤器
*/
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 {
  }
}
//自定义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;
  }
}

这个也是在网上找的一些大神写的,一般情况下,SpringMVC默认的乱码处理就已经能够很好的解决了!
然后在web.xml中配置这个过滤器即可!
乱码问题,需要平时多注意,在尽可能能设置编码的地方,都设置为统一编码 UTF-8