springmvc-大总结-胜哥

SpringMVC

第一章 初识SpringMVC

1.1 SpringMVC简介

  • SpringMVC是Spring 为【展现层、表述层、表示层、控制层】提供的基于 MVC 设计理念的优秀的 Web 框架
  • Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器【处理器】,而无须实现任何接口。

1.2 SpringMVC流程简图

image-20220314090529223

1.3 搭建SpringMVC框架

  • 创建web工程【day02_01视频】

  • 设置打包方式war包

  • 导入相关jar包【day01Maven笔记_5.7 Maven 依赖管理】

    <!--spring-webmvc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.1</version>
    </dependency>
    
    <!-- 导入thymeleaf与spring5的整合包 -->
    <dependency>
        <groupId>org.thymeleaf</groupId>
        <artifactId>thymeleaf-spring5</artifactId>
        <version>3.0.12.RELEASE</version>
    </dependency>
    
    <!--servlet-api-->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
        <scope>provided</scope>
    </dependency>
    
  • 编写web.xml配置文件

    • 配置前端控制器【DispatcherServlet】
      • url配置为【/】
      • 配置初始化参数
      • 设置Servlet优先级
  • 编写springmvc.xml配置文件

    • 开启组件扫描
    • 装配视图解析器【ThymeleafViewResolver】
  • 装配控制器【Controller】

    • @Controller
    • @RequestMapping("/helloworld")
  • 发送请求【进行测试】

第二章 @RequestMapping注解详解

2.1 @RequestMapping注解位置

源码:@Target({ElementType.TYPE, ElementType.METHOD})

  • @RequestMapping可以书写在类上面
    • 为指定类映射URL
    • 不能单独使用,配合方法使用
  • @RequestMapping可以书写在方法上面
    • 为指定方法映射URL
    • 可以单独使用

2.2 @RequestMapping注解属性

  • path:

    • 类型:String[]
    • 作用:为指定方法或类映射路径【URL】
  • value:

    • 类型:String[]
    • 作用:与path属性作用一致
  • method:

    • 类型:RequestMethod[]

    • 作用:为URL设置请求方式,如接收不支持请求方式会报错:405

      Request method 'GET' not supported
      
    • RequestMethod类型是一个枚举

      public enum RequestMethod {
         GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
      }
      
  • params:

    • 类型:String[]

    • 作用:为URL设置请求参数【请求当前URL必须携带指定的请求参数,如未携带会报错:400】

      Parameter conditions "stuName" not met for actual request parameters
      
  • headers:

    • 类型:String[]

    • 作用:为URL设置请求头信息【请求当前URL必须携带指定请求头,如未携带会报错:404】

      源服务器未能找到目标资源的表示或者是不愿公开一个已经存在的资源表示。
      

2.3 @RequestMapping注解支持Ant风格URL

  • Ant风格三种通配符

    • ?:匹配单个字符
    • *:匹配单层多个任意字符
    • **:匹配多层多个任意字符
  • 示例代码

    /**
         * 测试RequestMapping注解中params&headers属性
         * @return
         */
    @RequestMapping(value = "/testRmAnt/**")
    public String testRmAnt(){
        System.out.println("==>testRmAnt()!!!");
        return "success";
    }
    

2.4 @RequestMapping支持占位符风格URL

  • 定义占位符语法:{}

  • 获取占位符数据:@PathVariable

    • 属性
      • name:设置入参占位符名称
      • value:与name属性作用一致
      • required:设置当前参数是否必须入参
        • true【默认值】:必须入参,如未入参会报错
        • false:不必须入参,如未入参会显示默认值:null
  • 示例代码

    <a th:href="@{/HelloController/testPathVariable/1001/zs}">测试@PathVariable</a><br>
    
    /**
     * 测试@PathVariable
     * @return
     */
    @RequestMapping(value = "/testPathVariable/{stuId}/{stuName}")
    public String testPathVariable(@PathVariable("stuId") Integer stuId,
                                   @PathVariable("stuName") String stuName){
        System.out.println("==>testPathVariable()!!!stuId:"+stuId);
        System.out.println("stuName = " + stuName);
        return "success";
    }
    

第三章 REST【RESTful】风格CRUD

3.1 REST风格CRUD概述

  • 通过请求方式不同,执行不同业务功能
  • GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。
  • 使用REST风格CRUD优势
    • 提高网址排名
      • 竞价排名
      • 技术优化
    • 便于第三方平台对接

3.2 REST风格与传统风格对比

  • 传统风格:通过URL不同,执行不同业务功能

    • 业务 URL 请求方式
    • 增加 /saveUser POST
    • 删除 /deleteUser?id=1001 GET
    • 修改 /updateUser POST
    • 查询 /getUser?id=1001 GET
  • REST风格:通过请求方式不同,执行不同业务功能

    • 业务 URL 请求方式
    • 增加 /user POST
    • 删除 /user/1001 DELETE
    • 修改 /user PUT
    • 查询 /user/1001 GET

3.3 源码解析HiddenHttpMethodFilter

StringUtils:Spring提供字符串工具类

  • 使用HiddenHttpMethodFilter作用

  • 帮助发送【DELETE&PUT】请求方式

  • 使用HiddenHttpMethodFilter步骤

    1. 在web.xml中注册HiddenHttpMethodFilter

      <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>
      
    2. 提交方式必须是:POST

    3. 必须参数名为:_method的请求参数

      <base th:href="@{/}">
      <form action="user/1001" method="post">
          <input type="hidden" name="_method" value="DELETE">
          <input type="submit" value="删除User">
      </form>
      
public static final String DEFAULT_METHOD_PARAM = "_method";

private String methodParam = DEFAULT_METHOD_PARAM;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

   HttpServletRequest requestToUse = request;

   if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
      String paramValue = request.getParameter(this.methodParam);
      if (StringUtils.hasLength(paramValue)) {
         String method = paramValue.toUpperCase(Locale.ENGLISH);
         if (ALLOWED_METHODS.contains(method)) {
            requestToUse = new HttpMethodRequestWrapper(request, method);
         }
      }
   }

   filterChain.doFilter(requestToUse, response);
}


/**
 * Simple {@link HttpServletRequest} wrapper that returns the supplied method for
 * {@link HttpServletRequest#getMethod()}.
 */
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {

   private final String method;

   public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
      super(request);
      this.method = method;
   }

   @Override
   public String getMethod() {
      return this.method;
   }
}

day11

第四章 SpringMVC处理请求数据【重点】

JavaWeb处理请求数据【HttpServletRequest&HttpServletResponse】

  • 获取请求参数:request.getParameter()
    • URL中参数:/user?id=1001
    • 请求体中参数
  • 获取请求头:request.getHeader()
  • 获取Cookie:request.getCookies()

4.1 获取请求参数

  • 默认情况:SpringMVC默认会将参数名与入参名一致的参数,自动入参

  • @RequestParam注解

    • 作用:当参数名与入参名不一致时,可以设置指定参数名入参
    • 属性
      • name:设置指定入参的参数名
      • value:与name属性作用一致
      • required:设置当前参数是否必须入参,默认值:true
        • true:必须入参,未入参会报错:400
        • false:不必须入参,未入参不会报错【默认值:null】
      • defaultValue:设置入参默认值
  • POJO入参

    • 相关底层
      • POJO入参是调用setXXX()方法
    • 注意:必须要保证请求参数名与POJO的属性名保持一致
    • 示例代码
  • 示例代码

    @RequestMapping(value = "/doRequestParam")
    public String doRequestParam(String stuName,
                                 @RequestParam(value = "studentId",required = false,defaultValue = "8888") Integer stuId){
        System.out.println("stuId = " + stuId);
        System.out.println("stuName = " + stuName);
        return SUCCESS;
    }
    
    @RequestMapping("/doResultPOJOParam")
    public String doResultPOJOParam(Employee employee){
        System.out.println("employee = " + employee);
        return SUCCESS;
    }
    

4.2 获取请求头

  • 语法:@RequestHeader

  • 作用:获取请求头信息

  • 属性:

    • name:设置指定请求头的参数名
    • value:与name属性作用一致
    • required:设置当前请求头是否必须入参,默认值:true
      • true:必须入参,未入参会报错:400
      • false:不必须入参,未入参不会报错【默认值:null】
    • defaultValue:设置入参默认值
  • 示例代码

    @RequestMapping("/doRequestHeader")
    public String doRequestHeader(@RequestHeader("User-Agent") String userAgent){
        System.out.println("userAgent = " + userAgent);
        return SUCCESS;
    }
    

4.3 获取Cookie信息

  • 语法:@CookieValue

  • 作用:获取Cookie信息

  • 属性

    • name:设置指定CookieName的参数名
    • value:与name属性作用一致
    • required:设置当前Cookie是否必须入参,默认值:true
      • true:必须入参,未入参会报错:400
      • false:不必须入参,未入参不会报错【默认值:null】
    • defaultValue:设置Cookie默认值
  • 示例代码

    @RequestMapping("/doRequestCookie")
    public String doRequestCookie(@RequestHeader("Cookie") String cookie,
                                  @CookieValue("stuName") String cookieValue,
                                  HttpServletResponse response){
        Cookie ck = new Cookie("stuName","ll");
        response.addCookie(ck);
        System.out.println("cookie = " + cookie);
        System.out.println("cookieValue = " + cookieValue);
        return SUCCESS;
    }
    

4.4 使用Servlet原生API

  • 将相应对象直接入参即可直接使用

     @RequestMapping("/doRequestCookie")
        public String doRequestCookie(@RequestHeader("Cookie") String cookie,
                                      @CookieValue("stuName") String cookieValue,
                                      HttpServletResponse response,
                                      HttpServletRequest request,
                                      HttpSession session){
            ServletContext servletContext = request.getServletContext();
    //        HttpSession session = request.getSession();
            ServletContext servletContext1 = session.getServletContext();
    

第五章 SpringMVC处理响应数据【重点】

源码解析ModelAndView

public class ModelAndView {

/** View instance or view name String. */
//View:是一个View对象或view名称【建议使用view名称】
@Nullable
private Object view;

/** Model Map. */
//ModelMap:是spring框架封装一个类,ModelMap extends LinkedHashMap<String, Object>
@Nullable
private ModelMap model;


/**
	 * Set a view name for this ModelAndView, to be resolved by the
	 * DispatcherServlet via a ViewResolver. Will override any
	 * pre-existing view name or View.
	 */
	public void setViewName(@Nullable String viewName) {
		this.view = viewName;
	}

	/**
	 * Return the view name to be resolved by the DispatcherServlet
	 * via a ViewResolver, or {@code null} if we are using a View object.
	 */
	@Nullable
	public String getViewName() {
		return (this.view instanceof String ? (String) this.view : null);
	}


    /**
	 * Return the model map. May return {@code null}.
	 * Called by DispatcherServlet for evaluation of the model.
	 */
	@Nullable
	protected Map<String, Object> getModelInternal() {
		return this.model;
	}

	/**
	 * Return the underlying {@code ModelMap} instance (never {@code null}).
	 */
	public ModelMap getModelMap() {
		if (this.model == null) {
			this.model = new ModelMap();
		}
		return this.model;
	}

	/**
	 * Return the model map. Never returns {@code null}.
	 * To be called by application code for modifying the model.
	 */
	public Map<String, Object> getModel() {
		return getModelMap();
	}

    /**
	 * Add an attribute to the model.
	 * @param attributeName name of the object to add to the model (never {@code null})
	 * @param attributeValue object to add to the model (can be {@code null})
	 * @see ModelMap#addAttribute(String, Object)
	 * @see #getModelMap()
	 */
	public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) {
		getModelMap().addAttribute(attributeName, attributeValue);
		return this;
	}

	/**
	 * Add an attribute to the model using parameter name generation.
	 * @param attributeValue the object to add to the model (never {@code null})
	 * @see ModelMap#addAttribute(Object)
	 * @see #getModelMap()
	 */
	public ModelAndView addObject(Object attributeValue) {
		getModelMap().addAttribute(attributeValue);
		return this;
	}

}

5.1 处理响应数据方式一

  • 语法:使用ModelAndView对象作为方法返回值类型,处理响应数据

  • 底层实现原理

    • 数据共享到request域
    • 跳转路径方式:转发
  • 示例代码

    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        ModelAndView mv = new ModelAndView();
        //设置数据【将数据共享到域中】
        mv.addObject("stuName","lilong");
        //设置视图【转发或重定向】
        mv.setViewName("response_success");
        return mv;
    }
    
    <h2>测试响应数据-成功页面</h2>
    stuName:<span th:text="${stuName}"></span>
    

5.2 处理响应数据方式二

  • 语法:使用Map或Model或ModelMap作为参数入参,处理响应数据

  • 底层实现原理

    • 数据共享到request域
    • 跳转路径方式:转发
  • 示例代码

     @RequestMapping("/testModelOrModelMapOrMap")
        public String testModelOrModelMapOrMap(Model model/*Map<String,Object> map*/){
            //设置数据
    //        map.put("stuName","lisi");
            model.addAttribute("stuName","wangwu");
    
            return "response_success";
        }
    

5.3 如何将数据共享到session域

@SessionAttributes("stuName")   //将request域数据,同步session域中
public class ResponseDataController {
    /**
     * 了解
     * @param map
     * @return
     */
    @RequestMapping("/testSession")
    public String testSession(/*HttpSession session*/ Map<String,Object> map){
        //设置数据[session域]
//        session.setAttribute("stuName","zhaoliu");

        map.put("stuName","zhaoliu");

        return "response_success";
    }
}

第六章 SpringMVC 处理请求与响应乱码问题【重点】

JavaWeb解决乱码:三行代码

  • 解决POST请求乱码
    • request.setCharacterEncoding("UTF-8");
  • 解决GET请求乱码【Tomcat8及以后,自动解决】
  • 解决响应乱码
    • response.setCharacterEncoding("GBK");
    • response.setContentType("text/html;charset=UTF-8");

6.1 源码解析CharacterEncodingFilter

public class CharacterEncodingFilter extends OncePerRequestFilter {

   @Nullable
   private String encoding;

   private boolean forceRequestEncoding = false;

   private boolean forceResponseEncoding = false;
    
    public void setForceEncoding(boolean forceEncoding) {
		this.forceRequestEncoding = forceEncoding;
		this.forceResponseEncoding = forceEncoding;
	}
    
    @Override
	protected void doFilterInternal(
			HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		//字符集
		String encoding = getEncoding();
		if (encoding != null) {
			if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
				//解决请求乱码
                request.setCharacterEncoding(encoding);
			}
			if (isForceResponseEncoding()) {
				//解决响应乱码
                response.setCharacterEncoding(encoding);
			}
		}
		filterChain.doFilter(request, response);
	}
    
    
}

6.2 使用CharacterEncodingFilter步骤

  • 注意:CharacterEncodingFilter必须注册在第一个过滤器位置
  1. 注册CharacterEncodingFilter
  2. 为CharacterEncodingFilter设置初始化参数
<!--    注册CharacterEncodingFilter解决乱码问题【必须是第一个过滤器位置】-->
<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>

第七章 SpringMVC中视图对象及视图解析器对象

7.1 视图解析器对象【ViewResolver】

  • 概述:SpringMVC中所有视图解析器对象均实现ViewResolver接口
  • 作用:使用ViewResolver,将View从ModelAndView中解析出来
    • 在springMVC中无论方法返回的是ModelAndView还是String,最终底层封装为ModelAndView

7.2 视图对象【View】

  • 概述:SpringMVC中所有视图对象【View】均实现的View接口

  • 作用:视图渲染

    • 将数据共享到域中【request、session、application(ServletContext)】
    • 跳转路径【转发或重定向】
  • 常用的视图对象

    • ThymeleafView

    • RedirectView

      if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
          vrlogger.trace("[THYMELEAF] View \"{}\" is a redirect, and will not be handled directly by ThymeleafViewResolver.", viewName);
          final String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length(), viewName.length());
          final RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
          return (View) getApplicationContext().getAutowireCapableBeanFactory().initializeBean(view, REDIRECT_URL_PREFIX);
      }
      

7.3 源码解析SpringMVC工作原理_入门

  • DispatcherServlet:1061行代码如下【前端控制器调用Controller的入口】

    //1061行代码【前端控制器调用Controller的入口】
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    //1078行代码【【前端控制器处理ModelAndView对象的入口】】
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    //1139行代码【渲染视图入口】		
    render(mv, request, response);
    //1371行代码【视图解析器作用源码】
    view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
    //1394行代码【视图对象作用源码】
    view.render(mv.getModelInternal(), request, response);
    
    
    • 进入【1371行代码】resolveViewName()方法内部

      @Nullable
      protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
            Locale locale, HttpServletRequest request) throws Exception {
         if (this.viewResolvers != null) {
            for (ViewResolver viewResolver : this.viewResolvers) {
                //视图解析器,通过viewName解析出View对象
                View view = viewResolver.resolveViewName(viewName, locale);
               if (view != null) {
                  return view;
               }
            }
         }
         return null;
      }
      
    • 进入【1394行代码】view.render(mv.getModelInternal(), request, response);

      ThymeleafView对象

      //解决响应乱码
      response.setContentType(computedContentType);
      
    • 在WebEngineContext类的setVariable方法的467行将模型数据放到了request域

      //springMVC底层将数据共享到request域
      this.request.setAttribute(name, value);
      

7.4 SpringMVC中重定向

  • 语法:方法的返回值设置如下

  • return "redirect:/xxx.html"

  • 示例代码

    /**
        测试重定向
     */
    @RequestMapping("/testRedirect")
    public String testRedirect(){
        System.out.println("=====>测试重定向");
        return "redirect:/hello.html";
    }
    
  • 源码:ViewResolver

    //路径中使用redirect:/开头,相当于使用绝对路径
    if (this.contextRelative && getUrl().startsWith("/")) {
       // Do not apply context path to relative URLs.
       targetUrl.append(getContextPath(request));
    }
    targetUrl.append(getUrl());
    
    //RedirectView627行代码,重定向源码
    response.sendRedirect(encodedURL);
    

第八章 SpringMVC中视图控制器【View-Controller标签】

  • 语法:

    <mvc:view-controller path="/URL" view-name="视图名称"></mvc:view-controller>
    
  • 作用:将path中URL映射到view-name的逻辑视图名,通过viewResolver将逻辑视图名转换并跳转物理视图

  • 示例代码

    <mvc:view-controller path="/" view-name="index"></mvc:view-controller>
    <mvc:view-controller path="/toRestPage" view-name="rest_page"></mvc:view-controller>
    

第九章 SpringMVC解决静态资源加载问题

9.1 静态资源包含以下几点

  • html
  • css
  • js
  • img
  • 等等。。。

9.2 服务器默认DefaultServlet加载静态资源

  • DefaultServlet与DispatcherServlet的URL配置冲突了【都是/】,导致DefaultServlet失效【无法加载静态资源】
<servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
	<servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

9.3 解决静态资源加载问题

<!--    springMVC提供静态资源处理器-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>

<!--    解决静态资源加载后续问题:导致Controller失效【@RequsetMapping无法使用】 -->
<mvc:annotation-driven></mvc:annotation-driven>

day12

第十章 实现REST风格CRUD

10.1 实现删除功能思路

  • 方式一:将超链接改成表单提交

    • 不足:更换样式
    <form th:action="@{/emps/}+${emp.id}" method="post">
        <input type="hidden" name="_method" value="DELETE">
        <input type="submit" value="删除员工信息">
    </form>
    
  • 方式二:使用超链接方式

    • 单击超链接后,获取当前超链接href属性值:x

    • 将x赋值给表单【以DELETE方式提交表单】action属性中

    • 提交表单

    • 取消超链接默认行为

    • 示例代码

      <a th:name="${emp.lastName}" th:href="@{/emps/}+${emp.id}" @click="deleteEmpById">删除</a>
      <form id="delForm" action="#" method="post">
          <input type="hidden" name="_method" value="DELETE">
      </form>
      
      <script type="text/javascript" src="static/js/vue_v2.6.14.js"></script>
      <script type="text/javascript">
          var vm = new Vue({
              el:"#app",
              data:{
              },
              methods:{
                  deleteEmpById(){
                      //获取员工姓名
                      var lastName = event.target.name;
                      var rs = confirm("确定删除【"+lastName+"】员工信息吗?");
                      if(rs){
                          //1. 单击超链接后,获取当前超链接href属性值:x
                          var x = event.target.href;
                          //2. 将x赋值给表单【以DELETE方式提交表单】action属性中
                          var delFormEle = document.getElementById("delForm");
                          delFormEle.action = x;
                          //3.提交表单
                          delFormEle.submit();
                      }
                      //4.取消超链接默认行为【不以超链接方式提交】
                      event.preventDefault();
                  }
              }
          });
      
      </script>
      

第十一章 SpringMVC 中消息转换器

11.1 消息转换器

  • 概述:HttpMessageConverter 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息。

  • 作用:将对象【POJO】与请求报文或响应报文相互转换

    image-20220317111414997

11.2 使用消息转换器获取请求信息

  • 使用@RequestBody注解参入,获取请求体信息

    • 示例代码

      <h2>测试@RequestBody</h2>
      <form th:action="@{/testRequestBody}" method="get">
          empName:<input type="text" name="empName"><br>
          <input type="submit" value="提交">
      </form>
      
      @RequestMapping("/testRequestBody")
      public String testRequestBody(@RequestBody(required = false) String rquestBody){
          System.out.println("rquestBody = " + rquestBody);
          return SUCCESS;
      }
      
    • 注意:以get请求方式提交表单,不能为@RequestBody注解注入请求体信息。因为get提交方式没有请求体。

  • 使用HttpEntity入参,获取请求报文信息

    • 获取请求头

    • 获取请求体

    • 示例代码

      <h2>测试HttpEntity</h2>
      <form th:action="@{/testHttpEntity}" method="POST">
          empName:<input type="text" name="empName"><br>
          <input type="submit" value="提交">
      </form>
      
      /**
       * 测试HttpEntity
       * @param httpEntity
       * @return
       */
      @RequestMapping("/testHttpEntity")
      public String testHttpEntity(HttpEntity<String> httpEntity){
          //获取请求头
          HttpHeaders headers = httpEntity.getHeaders();
          System.out.println("headers = " + headers);
          //获取请求体
          String body = httpEntity.getBody();
          System.out.println("body = " + body);
          return SUCCESS;
      }
      
  • 注意:如果没有请求体,也不会报错【null】。

11.3 使用消息转换器处理响应数据

  • 使用@ResponseBody注解,响应数据

    • 位置:标识在方法上面

    • 作用:将数据以响应流的方式,响应数据

    • 示例代码

      <h2>测试@ResponseBody</h2>
      <a th:href="@{/testResponseBody}">测试@ResponseBody</a>
      
      @ResponseBody
      @RequestMapping("/testResponseBody")
      public String testResponseBody(){
          System.out.println("====>testResponseBody!!!");
          return "zhangsan";
      }
      

11.4 使用消息转换器处理Json数据【重要】

  • 导入jar包

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.12.3</version>
    </dependency>
    
  • 配置消息转换器:MappingJackson2HttpMessageConverter,处理Json格式数据

    <mvc:annotation-driver />
    
  • @ResponseBody注解添加需要转换Json格式的方法上面

第十二章 SpringMVC中文件上传与下载

12.1 文件下载

  • 语法:使用ResponseEntity对象作为方法返回值类型,实现文件下载

  • 实现文件下载逻辑

    • 读取服务器资源
    • 写浏览器端
  • 实现步骤

    1. 准备资源

    2. 实现代码

    3. 示例代码

      /**
       * 实现文件下载
       * @return
       */
      @RequestMapping("/doFileDownLoad")
      public ResponseEntity<byte[]> doFileDownload(String fileName,
                                                   HttpServletRequest request){
          ResponseEntity<byte[]> responseEntity = null;
      
          try {
              //目标资源【真实路径】
              String realPath =
                      request.getServletContext().getRealPath("/WEB-INF/download/" + fileName);
              System.out.println("realPath = " + realPath);
              //创建输入流
              InputStream is = new FileInputStream(realPath);
              //创建byte[]
              byte[] bytes = new byte[is.available()];
              //将下载目标资源,读bytes[]中
              is.read(bytes);
      
              //准备请求头
              HttpHeaders headers = new HttpHeaders();
              //设置请求头相关参数
              //设置当前文件为附件格式【通知浏览器别打开,下载】
              headers.add("Content-Disposition", "attachment;filename="+fileName);
              //处理中文文件名问题
              headers.setContentDispositionFormData("attachment", new String(fileName.getBytes("utf-8"), "ISO-8859-1"));
      
              //使用三个参数构造器【下载目标资源byte[]数组,请求头,状态码】
              responseEntity = new ResponseEntity<>(bytes,headers, HttpStatus.OK);
      
          } catch (Exception e) {
              e.printStackTrace();
          }
      
          return responseEntity;
      }
      

12.2 文件上传

  • 语法:使用CommonsMultipartResolver 实现文件上传

  • 实现文件上传步骤

    1. 导入jar包

      <!-- commons-fileupload -->
      <dependency>
          <groupId>commons-fileupload</groupId>
          <artifactId>commons-fileupload</artifactId>
          <version>1.4</version>
      </dependency>
      
    2. 装配CommonsMultipartResolver

      • id必须是multipartResolver
    3. html页面

      • method="post"
      • enctype="multipart/form-data"
      • type="file"
    4. 在Controller层的文件上传方法中入参:MultipartFile

  • 优化文件上传

    • 允许同名文件上传

      • 使用UUID处理文件名【时间戳+id】
      • UUID是一个十六进制32位随机数【全球唯一】
    • 上传文件大小的上限

      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
          <!--        设置字符集UTF-8    -->
          <property name="defaultEncoding" value="UTF-8"></property>
          <!--        设置文件上传大小上限-->
          <property name="maxUploadSize" value="102400"></property>
      </bean>
      

第十三章 SpringMVC中拦截器

13.1 拦截器与过滤器区别

  • 过滤器【Filter】属于web服务器端组件
    • 过滤器主要作用:过滤Servlet
    • 执行时机:执行Servlet前和执行Servlet后
  • 拦截器【Interceptor】属于框架
    • 拦截器主要作用:拦截Controller
    • 拦截器3个执行时机:
      1. 位置1:在DispatcherServlet后,Controller之前【请求】
      2. 位置2:Controller之后,DispatcherServlet之前【响应】
      3. 位置3:在DispatcherServlet之后【响应】
  • 图解

拦截器与过滤器区别

13.2 拦截器概述

  • Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter 适配器类。
  • 实现拦截器两种方式
    • 实现接口:HandlerInterceptor
    • 继承类:HandlerInterceptorAdapter
  • HandlerInterceptor三个方法
    • preHandle():这个方法在业务处理器处理请求之前被调用,可以在此方法中做一些权限的校验。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
    • postHandle():这个方法在业务处理器处理请求之后,渲染视图之前调用。在此方法中可以对ModelAndView中的模型和视图进行处理。
    • afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

13.3 实现拦截器步骤

  • 创建拦截器【实现接口或继承类】

  • 重写三个方法

  • 在springMVC.xml配置文件中,配置拦截器

    • 全局配置:为每个Controller中的URL均配置了当前拦截器

      <mvc:interceptors>
      <!--        <ref bean="myInterceptor"></ref>-->
              <bean class="com.atguigu.Interceptor.MyInterceptor"></bean>
          </mvc:interceptors>
      
    • 局部配置:为指定URL配置当前拦截器

      <mvc:interceptors>
          <mvc:interceptor>
              <mvc:mapping path="/TestInterceptorController"/>
              <bean class="com.atguigu.Interceptor.MyInterceptor"></bean>
          </mvc:interceptor>
      </mvc:interceptors>
      

13.4 拦截器工作原理

  • 单个拦截器工作原理
  1. 请求【浏览器向服务器发送请求:Controller】
  2. 执行拦截器preHandle()
  3. 执行Controller中处理方法
  4. 执行拦截器postHandle()
  5. DispatcherServlet视图渲染
  6. 执行拦截器afterCompletion()
  7. 响应【响应数据|路径跳转】
  • 多个拦截器工作原理
  1. 请求【浏览器向服务器发送请求:Controller】
  2. 执行拦截器1preHandle()
  3. 执行拦截器2preHandle()
  4. 执行Controller中处理方法
  5. 执行拦截器2postHandle()
  6. 执行拦截器1postHandle()
  7. DispatcherServlet视图渲染
  8. 执行拦截器2afterCompletion()
  9. 执行拦截器1afterCompletion()
  10. 响应【响应数据|路径跳转】
  • afterComplection源码

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
       for (int i = this.interceptorIndex; i >= 0; i--) {
          HandlerInterceptor interceptor = this.interceptorList.get(i);
          try {
             interceptor.afterCompletion(request, response, this.handler, ex);
          }
          catch (Throwable ex2) {
             logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
          }
       }
    }
    

13.5 preHandle()返回值问题

  • 第一个拦截器1preHandle()方法,返回false时,只执行拦截器1preHandle()就结束
  • 不是第一个拦截器2的preHandle()方法,返回false时。
    • 执行拦截器2之前的拦截器1的preHandle()方法及拦截器2的preHandle()方法,最后执行拦截器1的afterCompletion()方法

第十四章 Spring中异常处理器

14.1 为什么需要处理异常

  • 如程序出现异常未处理,会导致程序终止【宕机】
  • JavaSE异常处理机制
    • try-catch-finally
    • thow或throws

14.2 SpringMVC异常处理器

  • Spring MVC 通过 HandlerExceptionResolver 处理程序的异常,包括 Handler 映射、数据绑定以及目标方法执行时发生的异常。

  • 需要掌握异常处理器如下:

    • DefaultHandleExceptionResolver
      • 默认异常处理器,默认开启,支持10+多个异常处理。
    • SimpleMappingExceptionResolver
      • 支持自定义异常处理,作用:将指定异常跳转到指定页面
      • 装配异常处理器【SimpleMappingExceptionResolver】
  • 装配SimpleMappingExceptionResolver

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="java.lang.NullPointerException">error_np</prop>
                <prop key="java.lang.ArithmeticException">error_am</prop>
            </props>
        </property>
    </bean>
    
  • 总结:SpingMVC底层处理器异常后,会返回ModelAndView对象

第十五章 SpringMVC工作原理

15.1 扩展三个对象

  • HandlerAdapter【请求处理器适配器对象】

    • 作用:调用Controller中相应方法

      mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      
  • HandlerExecutionChain【请求处理器执行链对象】

    • 作用:创建HandlerAdapter对象

    • 描述

      //官网面试
      * Handler execution chain, consisting of handler object and any handler interceptors.
      //自己理解:HandlerExecutionChain是一个类,由当前请求处理器和对应所有拦截器组成。
      
  • HandlerMapping【请求处理器映射器对象】

    • 作用:创建HandlerExecutionChain对象

    • 描述

      //官方描述
      Interface to be implemented by objects that define a mapping between
      requests and handler objects.
      //自己理解:HandlerMapping是一个接口,定义一个映射关系,所有请求与请求处理器的映射关系
      

15.2 SpringMVC工作原理1

  1. 请求【浏览器向服务器发送请求】

  2. 通过DispatcherServlet加载Controller,从而判断URL是否存在?

    • 不存在:判断是否配置【<mvc:default-servlet-handler></mvc:default-servlet-handler>】

      • 配置:出现404现象,并提示URL不可用

        image-20220318111910877

      • 未配置:出现404现象,但不会提示URL信息

        image-20220318112006981

  • 简图总结

    image-20220318113202437

15.3 SpringMVC工作原理2

  1. 请求【浏览器向服务器发送请求】

  2. 通过DispatcherServlet加载Controller,从而判断URL是否存在?

    • 存在
      • 先通过HandlerMapping创建HandlerExecutionChain对象
      • 再通过HandlerExecutionChain创建HandlerAdapter对象
  3. 执行Interceptor的第一个方法【preHandle()】

    //DispatcherServlet的1056行代码
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
       return;
    }
    
  4. 执行Controller中的相应方法

    //DispatcherServlet的1061行代码mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
  5. 判断请求处理器中是否存在异常【Controller中是否报错】

    • 存在异常
      • 通过HandlerExceptionResolver异常处理器处理异常,并返回ModelAndView
    • 不存在异常
      • 直接返回ModelAndView对象
      • 触发拦截器第二个方法【postHandle()】
  6. 通过ViewResolver将View从ModelAndView中解析出来

    //DispatcherServlet的1433行代码if (this.viewResolvers != null) {   for (ViewResolver viewResolver : this.viewResolvers) {      View view = viewResolver.resolveViewName(viewName, locale);      if (view != null) {         return view;      }   }}
    
  7. View对象开始渲染视图

    • 将数据共享到域
    • 路径跳转
    //WebEngineContext中的782行代码// No matter if value is null or not. Value null will be equivalent to .removeAttribute()this.request.setAttribute(name, value);
    
  8. 执行拦截器第三个方法【afterCompletion】

    //DispatcherServlet的1157行代码mappedHandler.triggerAfterCompletion(request, response, null);
    
  9. 响应【响应数据|跳转页面】

  • 总结SpringMVC工作原理

    • 请求
    • 通过DispatcherServlet加载Controller,从而判断URL是否存在?【存在】
    • 执行拦截器第一个方法preHandle()
    • 执行Controller相应方法,处理请求做出响应
    • 执行拦截器第二个方法postHandle()
    • 通过ViewResolver将View从ModelAndView中解析出来
    • View对象开始渲染视图
    • 执行拦截器第三个方法afterCompletion()
    • 响应
  • 简图总结

    image-20220318113215081

第十六章 SSM框架整合

16.1 SSM整合思路

  • SpringMVC+Spring
    • 容器对象的管理问题
      • SpringMVC容器对象,由DispatcherServlet管理
      • Spring容器对象,由ContextLoaderListener管理
    • 解决组件扫描冲突问题
      • SpringMVC只扫描Controller层
      • Spring扫描排除Controller层
  • Mybatis+Spring
    • 数据源、事务管理冲突问题
      • 统一交个Spring框架管理
    • 使用Spring框架管理Mybatis核心对象
      • SqlSessionFactory
      • Mapper代理对象

16.2 SSM整合步骤及关键代码

  • SpringMVC+Spring步骤

    • 导入jar包

      <!--spring-webmvc--><dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-webmvc</artifactId>    <version>5.3.1</version></dependency><!-- 导入thymeleaf与spring5的整合包 --><dependency>    <groupId>org.thymeleaf</groupId>    <artifactId>thymeleaf-spring5</artifactId>    <version>3.0.12.RELEASE</version></dependency><!--servlet-api--><dependency>    <groupId>javax.servlet</groupId>    <artifactId>javax.servlet-api</artifactId>    <version>4.0.1</version>    <scope>provided</scope></dependency>
      
    • 配置文件

      • web.xml
        • 注册CharacterEncodingFilter,解决乱码问题
        • 注册HiddenHttpMethodFilter,支持REST风格CRUD
        • 注册DispatcherServlet,管理springMVC容器对象
        • 注册ContextLoaderListener,管理spring容器对象
        • 注册一个上下参数【contextConfigLocation】,设置spring.xml配置文件路径
      • springMVC.xml
        • 开启组件扫描【只扫描Controller层】
        • 装配视图解析器
        • 装配视图控制器【View-Controller】
        • 解决静态资源加载问题
        • 解决静态资源加载后续问题
      • spring.xml
        • 开启组件组件扫描【排除Controller层】
  • Mybatis+Spring

    • 导入jar包

      • Mybatis的jar包

        <!--导入druid的jar包--><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid</artifactId>    <version>1.1.10</version></dependency><!--导入mysql的jar包--><dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>5.1.37</version></dependency><!--mybatis--><dependency>    <groupId>org.mybatis</groupId>    <artifactId>mybatis</artifactId>    <version>3.5.7</version></dependency><!-- pagehelper --><dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper</artifactId>    <version>5.1.8</version></dependency>
        
      • Spring的jar包

        <!--spring-orm--><dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-orm</artifactId>    <version>5.3.1</version></dependency><!--spring-aspects--><dependency>    <groupId>org.springframework</groupId>    <artifactId>spring-aspects</artifactId>    <version>5.3.1</version></dependency>
        
      • Mybatis与Spring整合jar包

        <!--mybatis-spring--><dependency>    <groupId>org.mybatis</groupId>    <artifactId>mybatis-spring</artifactId>    <version>2.0.6</version></dependency>
        
    • 配置文件

      • mybatis-config.xml【Mybatis核心配置文件】
        • 设置别名
        • 开启驼峰式命名自动映射
        • 设置PageHelper分页插件
        • ....
      • xxxMapper.xml【映射文件】
        • SQL语句
      • spring.xml【spring配置文件】
        • 开启组件扫描【排除Controller】
        • 加载外部属性文件
        • 装配数据源【DruidDataSource】
        • 装配事务管理器【DataSourceTransactionManager】
        • 开启声明式事务管理注解支持
        • 装配SqlSessionFactoryBean,管理SqlSessionFactory
        • 装配MapperScannerConfigurer,管理Mapper代理对象

posted @   jiejie0830  阅读(100)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示