0
点赞
收藏
分享

微信扫一扫

关于springmvc的一篇学习笔记

云上笔记 2023-03-11 阅读 59

初识SpringMVC

SpringMVC概述

  • SpringMVC是Spring子框架

  • SpringMVC是Spring 为**【展现层|表示层|表述层|控制层】**提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的MVC 框架。

  • SpringMVC是非侵入式:可以使用注解让普通java对象,作为**请求处理器【Controller】**。

  • SpringMVC是用来代替Servlet

    Servlet作用

    1. 处理请求
      • 将数据共享到域中
    2. 做出响应
      • ​ 跳转页面【视图】

SpringMVC处理请求原理简图

  • 请求
  • DispatcherServlet【前端控制器】
    • 请求交给Controller|Handler
  • Controller|Handler【请求处理器】
    • 处理请求
    • 返回数据模型
  • ModelAndView
    • Model:数据模型
    • View:视图对象或视图名
  • DispatcherServlet视图渲染
    • 将数据共享到域中
    • 跳转页面【视图】
  • 响应

image-20220330160253730

SpringMVC搭建框架

搭建SpringMVC框架步骤

  • 创建工程【web工程】

  • 导入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注册DispatcherServlet【这里再创建web的时候一定要注意web.xml的路径是否选对】

      • url配置:/

      • init-param:contextConfigLocation,设置springmvc.xml配置文件路径【管理容器对象】

      • <load-on-startup>:设置DispatcherServlet优先级【启动服务器时,创建当前Servlet对象】

      • 代码示例

        <?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-name>dispatcherServlet</servlet-name>
                <!-- 如果这里不识别就看看web.xml路径配置是否正确 -->
                <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                <init-param>
                    <param-name>contextConfigLocation</param-name>
                    <param-value>classpath:springmvc.xml</param-value>
                </init-param>
                <load-on-startup>1</load-on-startup>
            </servlet>
            <servlet-mapping>
                <servlet-name>dispatcherServlet</servlet-name>
                <url-pattern>/</url-pattern>
            </servlet-mapping>
        </web-app>
        
    • springmvc.xml

      • 开启组件扫描
      • 配置视图解析器【解析视图(设置视图前缀&后缀)】
      <!--  装配视图解析器设置视图前缀和后缀  -->
      <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
          <!--配置字符集属性-->
          <property name="characterEncoding" value="UTF-8"/>
          <!-- 配置模板引擎属性-->
          <property name="templateEngine">
              <!-- 配置内部bean-->
              <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                  <!--配置模块解析器属性-->
                  <property name="templateResolver">
                      <!-- 配置内部bean-->
                      <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                          <!--配置前缀-->
                          <property name="prefix" value="/WEB-INF/pages/"></property>
                          <!-- 配置后缀-->
                          <property name="suffix" value=".html"/>
                          <!--配置字符集-->
                          <property name="characterEncoding" value="UTF-8"/>
                      </bean>
                  </property>
              </bean>
          </property>
      </bean>
      
  • 编写请求处理器【Controller|Handler】

    • 使用**@Controller**注解标识请求处理器

    • 使用**@RequestMapping**注解标识处理方法【URL】

    • 注意:

      image-20230103150315531

      idea在20.x版本以上要加上Static这样MVC才能识别出逻辑视图,但是也可以不加只不过他会有下划波浪线,提醒无法识别

      但是实际上是可以的

  • 准备页面进行,测试

@RequestMapping详解

@RequestMapping注解位置

@RequestMapping:为当前类,为当前方法设置映射URL

  • 书写在类上
    • 作用:为当前类设置映射URL
    • 注意:不能单独使用,需要与方法上的@RequestMapping配合使用,因为单独写在类上没有返回值,即没有逻辑视图就不知道跳转到那里
  • 方法上
    • 作用:为当前方法设置映射URL
    • 注意:可以单独使用

@RequestMapping注解属性

  • value属性

    • 类型:String[]
    • 作用:设置URL信息
  • path属性

    • 类型:String[]
    • 作用:设置URL信息
  • method属性

    • 类型:RequestMethod[]

      public enum RequestMethod {
      GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
      }
      
    • 作用:为当前URL【类或方法】设置请求方式【POST、DELETE、PUT、GET】

    • 注意:

      • 默认情况:所有请求方式均支持
      • 如请求方式不支持,会报如下错误
        • 405【Request method 'GET' not supported】
  • params

    • 类型:String[]
    • 作用:为当前URL设置请求参数
    • 注意:如设置指定请求参数,但URL中未携带指定参数,会报如下错误
      • 400【Parameter conditions "lastName" not met for actual request parameters:】
  • headers

    • 类型:String[]
    • 作用:为当前URL设置请求头信息
    • 注意:如设置指定请求头,但URL中未携带请求头,会报如下错误
      • 404:请求资源未找到
  • 代码示例

    public class Employee {
        @RequestMapping(value = {"/save","/insert"},method = RequestMethod.GET,
        params = "lastName",headers = "User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")
        public static String save(){
            System.out.println("添加");
            return "success";
        }
    }
    

@RequestMapping支持Ant 风格的路径(了解)

  • 常用通配符

    a) ?:匹配一个字符

    b) *:匹配任意字符

    c) **:匹配多层路径

  • 示例代码

    @RequestMapping("/testAnt/**")
        public static String testAnt(){
            System.out.println("测试ANT");
            return SUCCESS;
        }
    

@PathVariable 注解

@PathVariable注解位置

@Target(ElementType.PARAMETER)
  • 书写在参数前面

@PathVariable注解作用

  • 获取URL中占位符参数

  • 占位符语法:{}

  • 示例代码

    <a rel="nofollow" th:href="@{/EmpLise/testPathVariable/1010}">测试PathVariable</a>
    
    @RequestMapping("/testPathVariable/{empId}")
        public static String testPathVariable(@PathVariable("empId") Integer empId){
            System.out.println("empId==="+empId);
            return SUCCESS;
        }
    

@PathVariable注解属性

  • value属性
    • 类型:String
    • 作用:设置占位符中的参数名
  • name属性
    • 类型:String
    • 作用:与name属性的作用一致
  • required属性
    • 类型:boolean
    • 作用:设置当前参数是否必须入参【默认值:true】
      • true:表示当前参数必须入参,如未入参会报如下错误
        • Missing URI template variable 'empId' for method parameter of type Integer
      • false:表示当前参数不必须入参,如未入参,会装配null值

REST【RESTful】风格CRUD

  • 传统风格
功能 URL 请求方式
/insertEmp POST
/deleteEmp?empId=1001 GET
/updateEmp POST
/selectEmp?empId=1001 GET
  • REST风格CRUD
功能 URL 请求方式
/emp POST
/emp/1001 DELETE
/emp PUT
/emp/1001 GET

REST风格CRUD优势

  • 提高网站排名
    • 排名方式
      • 竞价排名
      • 技术排名
  • 便于第三方平台对接

实现PUT&DELETE提交方式步骤

  • 注册过滤器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>
    
  • 设置表单的提交方式为POST

    <h4>更新员工信息</h4><br>
    <form th:action="@{/emp}" method="post">
        <input type="hidden" name="_method" value="put">
        <input type="submit" value="修改员工信息">
    </form><br>
    <h4>删除员工信息</h4><br>
    <form th:action="@{/emp/1011}">
        <input type="hidden" name="_method" value="delete">
        <input type="submit" value="删除员工信息">
    </form>
    
  • 设置参数:_method=PUT或_method=DELETE

    <h4>删除员工信息</h4><br>
    <form th:action="@{/emp/1011}">
        <input type="hidden" name="_method" value="delete">
        <input type="submit" value="删除员工信息">
    </form>
    

源码解析HiddenHttpMethodFilter

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;//这个method是我们请求过来的method
		}
	}

SpringMVC处理请求数据

使用Servlet处理请求数据

  1. 请求参数
    • String param = request.getParameter();
  2. 请求头
    • request.getHeader();
  3. Cookie
    • request.getCookies();

处理请求参数

  • 默认情况:可以将请求参数名,与入参参数名一致的参数,自动入参【自动类型转换】
private static final String SUCCESS = "success";
    @RequestMapping("/param1")
    public static String test(String stu){
        System.out.println("stu===>"+stu);
        return SUCCESS;
    }
<a rel="nofollow" th:href="@{/param1(stu='zs')}">获取请求参数</a>
  • SpringMVC支持POJO入参

    • 要求:请求参数名与POJO的属性名保持一致

    • 示例代码

      <form th:action="@{/saveEmp}" method="POST">
          id:<input type="text" name="id"><br>
          LastName:<input type="text" name="lastName"><br>
          Email:<input type="text" name="email"><br>
          Salary:<input type="text" name="salary"><br>
          <input type="submit" value="添加员工信息">
      </form>
      
      /**
       * 获取请求参数POJO
       * @return
       */
      //pojo入参
          @RequestMapping("/param2")
          public static String test2(Employee employee){
              System.out.println(employee);
              return SUCCESS;
          }
      
  • @RequestParam注解

    • 作用:如请求参数与入参参数名不一致时,可以使用@RequestParam注解设置入参参数名

      private static final String SUCCESS = "success";
          @RequestMapping("/param1")
          //强制入参
          public static String test(@RequestParam("stu") String stud){
              System.out.println("stu===>"+stud);
              return SUCCESS;
          }
      
    • 属性

      • value

        • 类型:String
        • 作用:设置需要入参的参数名
      • name

        • 类型:String
        • 作用:与value属性作用一致
      • required

        • 类型:Boolean
        • 作用:设置当前参数,是否必须入参
          • true【默认值】:表示当前参数必须入参,如未入参会报如下错误
            • 400【Required String parameter 'stu' is not present】
          • false:表示当前参数不必须入参,如未入参,装配null值
      • defaultValue

        • 类型:String
        • 作用:当装配数值为null时,指定当前defaultValue默认值
        private static final String SUCCESS = "success";
            @RequestMapping("/param1")
            public static String test(String stu){
                System.out.println("stu===>"+stu);
                return SUCCESS;
            }
        

处理请头

  • 语法:@RequestHeader注解

  • 属性

    • value
      • 类型:String
      • 作用:设置需要获取请求头名称
    • name
      • 类型:String
      • 作用:与value属性作用一致
    • required
      • 类型:boolean
      • 作用:【默认值true】
        • true:设置当前请求头为必须入参,如未入参会报如下错误
        • false:表示当前参数不必须入参,如未入参,装配null值
    • defaultValue
      • 类型:String
      • 作用:当装配数值为null时,指定当前defaultValue默认值
//请求头参数
    @RequestMapping("/head")
    public static String test3(@RequestHeader("Accept-Language") String al,@RequestHeader("Referer") String ref){
        System.out.println(al+"++++="+ref);
        return SUCCESS;
    }
<a rel="nofollow" th:href="@{/head}">获取参数请求头</a>

处理Cookie信息

  • 语法:@CookieValue获取Cookie数值

  • 属性

    • value
      • 类型:String
      • 作用:设置需要获取Cookie名称
    • name
      • 类型:String
      • 作用:与value属性作用一致
    • required
      • 类型:boolean
      • 作用:【默认值true】
        • true:设置当前Cookie是否为必须入参,如未入参会报如下错误
          • 400【Required String parameter 'sName' is not present】
        • false:表示当前Cookie不必须入参,如未入参,装配null值
    • defaultValue
      • 类型:String
      • 作用:当装配数值为null时,指定当前defaultValue默认值
  • 示例代码

    @RequestMapping("/setCookie")
        public static String test4(HttpSession httpSession){
            System.out.println(httpSession.getId());
            return SUCCESS;
        }
        //获取cookie
        @RequestMapping("/getCookie")
        public static String test5(@CookieValue("JSESSIONID") String s){
            System.out.println("cookieValue"+s);
            return SUCCESS;
        }
    

SpringMVC处理响应数据

使用ModelAndView

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

  • ModelAndView是模型数据视图对象的集成对象,源码如下

    public class ModelAndView {
    
       /** View instance or view name String. */
       //view代表view对象或viewName【建议使用viewName】
       @Nullable
       private Object view;
    
       /** Model Map. */
       //ModelMap集成LinkedHashMap,存储数据
       @Nullable
       private ModelMap model;
        
        /**
        	设置视图名称
    	 */
    	public void setViewName(@Nullable String viewName) {
    		this.view = viewName;
    	}
    
    	/**
    	 * 获取视图名称
    	 */
    	@Nullable
    	public String getViewName() {
    		return (this.view instanceof String ? (String) this.view : null);
    	}
    
        /**
    	 获取数据,返回Map【无序,model可以为null】
    	 */
    	@Nullable
    	protected Map<String, Object> getModelInternal() {
    		return this.model;
    	}
    
    	/**
    	 * 获取数据,返回 ModelMap【有序】
    	 */
    	public ModelMap getModelMap() {
    		if (this.model == null) {
    			this.model = new ModelMap();
    		}
    		return this.model;
    	}
    
    	/**
    	 * 获取数据,返回Map【无序】
    	 */
    	public Map<String, Object> getModel() {
    		return getModelMap();
    	}
        
        /**
        	设置数据
        */
        public ModelAndView addObject(String attributeName, @Nullable Object attributeValue) {
    		getModelMap().addAttribute(attributeName, attributeValue);
    		return this;
    	}
        
        
    }
         
    
  • 示例代码

    @Controller
    public class TestResponse {
        @RequestMapping("/response")
        public ModelAndView test(){
            ModelAndView mv = new ModelAndView();
            //设置视图的名字
            mv.setViewName("Response_success");
            //设置共享的数据
            mv.addObject("stu","liu");
            return mv;
        }
    }
    
    
    1
    

使用Model、ModelMap、Map

  • 使用Model、ModelMap、Map作为方法入参,处理响应数据

  • 示例代码

    @RequestMapping("/toResponsem")
        public static  String modelMap(Map<String,Object> map /* Model model
                                            ModelMap modelMap*/){
            map.put("stu","zs");
            // model.addAttribute("stuName","lisi");
            // modelMap.addAttribute("stuName","wangwu");
            return "Response_success";
        }
    

SpringMVC中域对象

  • SpringMVC封装数据,默认使用request域对象

  • session域的使用

    • 方式1,用原生的session进行设置

      @RequestMapping("/tosession")
          public static  String see(HttpSession httpSession){
              httpSession.setAttribute("stu","zs");
              return "Response_success";
          }
      
    • 方式2,通过添加@SessionAttributes注解可以将请求域的内容一起设置到共享域

      @Controller
      @SessionAttributes("stu")
      public class TestResponse {
          @RequestMapping("/response")
          public ModelAndView test(){
              ModelAndView mv = new ModelAndView();
              //设置视图的名字
              mv.setViewName("Response_success");
              //设置共享的数据
              mv.addObject("stu","liu");
              return mv;
          }
      

SpringMVC处理请求响应乱码

源码解析CharacterEncodingFilter

public class CharacterEncodingFilter extends OncePerRequestFilter {

   //需要设置字符集
   @Nullable
   private String encoding;
   //true:处理请乱码
   private boolean forceRequestEncoding = false;
   //true:处理响应乱码
   private boolean forceResponseEncoding = false;
    
    public String getEncoding() {
		return this.encoding;
	}
    
    public boolean isForceRequestEncoding() {
		return this.forceRequestEncoding;
	}
    
    public void setForceResponseEncoding(boolean forceResponseEncoding) {
		this.forceResponseEncoding = forceResponseEncoding;
	}
    //设置修改字符集(请求乱码,响应乱码合二为一)
    public void setForceEncoding(boolean forceEncoding) {
		this.forceRequestEncoding = forceEncoding;
		this.forceResponseEncoding = forceEncoding;
	}
    
    
    public void setEncoding(@Nullable String encoding) {
		this.encoding = encoding;
	}
    
 	@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);
	
    }
    
    
}

CharacterEncodingFilter使用步骤

SpringMVC底层默认处理响应乱码,所有我们只需要处理请求乱码即可

  1. 注册CharacterEncodingFilter过滤器

    • 注意:注册CharacterEncodingFilter必须是第一Filter位置
  2. 为CharacterEncodingFilter中属性encoding赋值

  3. 为CharacterEncodingFilter中属性forceRequestEncoding赋值

  4. 代码示例

    <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>forceRequestEncoding</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
    

SpringMVC视图及视图解析器

视图解析器对象【ViewResolver】

  • 概述:ViewResolver接口的实现类或子接口,称之为视图解析器

  • 作用:将ModelAndView中的View对象解析出来

    • 在springMVC中无论方法返回的是ModelAndView还是String,最终底层封装为ModelAndView

    image-20220402111105304

视图对象【View】

  • 概述:View接口的实现类或子接口,称之为视图对象
  • 作用:视图渲染
    1. 将数据共享域中【request、session、application(SerletContext)】
    2. 跳转路径【转发或重定向】

源码解析SpringMVC工作原理

Controller中方法的返回值问题

  • 无论方法返回是ModelAndView还是String,最终SpringMVC底层,均会封装为ModelAndView对象

    //DispatcherServlet的1061行代码
    ModelAndView mv = null;
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
  • SpringMVC解析mv【ModelAndView】

    //DispatcherServlet的1078行代码
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    
  • ThymeleafView对象中344行代码【SpringMVC底层处理响应乱码】//在设置characterEncodingFilter那就只用解决请求乱码即可

    //computedContentType="text/html;charset=UTF-8"
    response.setContentType(computedContentType);
    
  • WebEngineContext对象中783行代码【SpringMVC底层将数据默认共享到request域】

    this.request.setAttribute(name, value);
    

视图及视图解析器源码

  • 视图解析器将View从ModelAndView中解析出来

    • ThymeleafViewResolver的837行代码

      //底层使用反射的方式,newInstance()创建视图对象
      final AbstractThymeleafView viewInstance = BeanUtils.instantiateClass(getViewClass());
      

视图控制器&重定向&加载静态资源

视图控制器

  • 语法:view-controller
    • 作用:当我们需要跳转的页面没有核心业务处理的时候,就没有必要再去创建一个控制器类,直接使用视图控制器即可
    • 步骤:
      • 添加<mvc:view-controller>标签:为指定URL映射html页面
      • 添加<mvc:annotation-driven>
        • 有20+种功能
        • 配置了<mvc:view-controller>标签之后会导致其他请求路径都失效,添加<mvc:annotation-driven>解决

重定向

  • 语法:return "**redirect:/**xxx.html";

加载静态资源

  • DefaultServlet加载静态资源到服务器

    • 静态资源:html、css、js等资源

    • tomcat->conf->web.xml关键代码如下:

      <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>
      
  • 发现问题

    • DispatcherServlet与DefaultServlet的URL配置均为:/,导致DispatcherServlet中的配置将DefaultServlet配置的/覆盖了【DefaultServlet失效,无法加载静态资源
  • 解决方案

    <!--    解决静态资源加载问题-->
    <mvc:default-servlet-handler></mvc:default-servlet-handler>
    <!-- 添加上述标签,会导致Controller无法正常使用,需要添加mvc:annotation-driven解决 -->
    <mvc:annotation-driven></mvc:annotation-driven>
    

源码解析重定向原理

  • 创建RedirectView对象【ThymeleafViewResolver的775行代码】

    // Process redirects (HTTP redirects)
    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);
    }
    
  • RedirectView视图渲染

    • RedirectView对象URL处理【330行代码】

      image-20220402144319392

    • 执行重定向【RedirectView的627行代码】

      image-20220402144419221

REST风格CRUD练习

搭建环境

  • 导入相关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
      • DispatcherServlet
    • springmvc.xml
      • 开启组件扫描
      • 装配视图解析器
      • 装配视图控制器
      • 解决静态资源加载问题
      • 装配annotation-driver
  • dao&pojo

    • employeePojo

      package SpringmvcRest.pojo;
      
      import org.springframework.stereotype.Component;
      
      @Component
      public class Employee {
          private Integer id;
          private String lastName;
          private String email;
          //1男,0女
          private Integer gender;
          private Department department;
      
          public Employee() {
          }
      
          public Employee(Integer id, String lastName, String email, Integer gender, Department department) {
              this.id = id;
              this.lastName = lastName;
              this.email = email;
              this.gender = gender;
              this.department = department;
          }
      
          public Employee(Integer id, String lastName, String email, Integer gender) {
              this.id = id;
              this.lastName = lastName;
              this.email = email;
              this.gender = gender;
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getLastName() {
              return lastName;
          }
      
          public void setLastName(String lastName) {
              this.lastName = lastName;
          }
      
          public String getEmail() {
              return email;
          }
      
          public void setEmail(String email) {
              this.email = email;
          }
      
          public Integer getGender() {
              return gender;
          }
      
          public void setGender(Integer gender) {
              this.gender = gender;
          }
      
          public Department getDepartment() {
              return department;
          }
      
          public void setDepartment(Department department) {
              this.department = department;
          }
      
          @Override
          public String toString() {
              return "Employee{" +
                      "id=" + id +
                      ", lastName='" + lastName + '\'' +
                      ", email='" + email + '\'' +
                      ", gender=" + gender +
                      ", department=" + department +
                      '}';
          }
      }
      
      
    • employeeDao

      package SpringmvcRest.dao;
      
      import SpringmvcRest.pojo.Department;
      import SpringmvcRest.pojo.Employee;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Repository;
      
      import java.util.Collection;
      import java.util.HashMap;
      import java.util.Map;
      @Repository
      public class EmployeeDao {
          private static Map<Integer, Employee> employees = null;
          @Autowired
          private DepartmentDao departmentDao;
      
          static {
              employees= new HashMap<Integer,Employee>();
              employees.put(1001,new Employee(1001,"E-AA","aa@163.com",1,new Department(101,"D-AA")));
              employees.put(1002,new Employee(1002,"E-BB","bb@163.com",1,new Department(102,"D-BB")));
              employees.put(1003,new Employee(1003,"E-CC","cc@163.com",1,new Department(103,"D-cc")));
              employees.put(1004,new Employee(1004,"E-DD","dd@163.com",1,new Department(104,"D-DD")));
              employees.put(1005,new Employee(1005,"E-EE","ee@163.com",1,new Department(105,"D-EE")));
          }
      
          private static Integer initId = 1006;
      
          /**
           * 添加员工,或者修改员工信息
           * @param employee
           * 先判断员工的id是否为空,为空就加入新id
           */
          public void save(Employee employee){
              if(employee.getId() == null){
                  employee.setId(initId++);
              }
              employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
              employees.put(employee.getId(),employee);
          }
      
          public Collection<Employee> getAll() {return employees.values();}
      
          public Employee get(Integer id){return  employees.get(id);}
      
          public void delete(Integer id){employees.remove(id);}
      }
      
      
    • departmentPojo

      package SpringmvcRest.pojo;
      
      import org.springframework.stereotype.Component;
      
      @Component
      public class Department {
          private Integer id;
          private String departmentName;
      
          @Override
          public String toString() {
              return "Department{" +
                      "id=" + id +
                      ", departmentName='" + departmentName + '\'' +
                      '}';
          }
      
          public Integer getId() {
              return id;
          }
      
          public void setId(Integer id) {
              this.id = id;
          }
      
          public String getDepartmentName() {
              return departmentName;
          }
      
          public void setDepartmentName(String departmentName) {
              this.departmentName = departmentName;
          }
      
          public Department(Integer id, String departmentName) {
              this.id = id;
              this.departmentName = departmentName;
          }
      
          public Department() {
          }
      
      
      }
      
      
    • departmentDao

      package SpringmvcRest.dao;
      
      import SpringmvcRest.pojo.Department;
      import SpringmvcRest.pojo.Employee;
      import org.springframework.stereotype.Repository;
      
      import java.util.Collection;
      import java.util.Collections;
      import java.util.HashMap;
      import java.util.Map;
      
      @Repository
      public class DepartmentDao {
      
          private static Map<Integer, Department> departments = null;
          static {
              departments =new HashMap<>();
              departments.put(101,new Department(101,"D-AA"));
              departments.put(102,new Department(102,"D-BB"));
              departments.put(103,new Department(103,"D-CC"));
              departments.put(104,new Department(104,"D-DD"));
              departments.put(105,new Department(105,"D-EE"));
          }
      
          public Collection<Department> getDepartment(){
              return departments.values();
          }
      
          public Department getDepartment(Integer id){
              return departments.get(id);
          }
      
      
      }
      
      

实现功能思路

  • 实现添加功能思路

    1. 跳转添加页面【查询所有部门信息】
    2. 实现添加功能
  • 实现删除功能思路

    1. 方式一:直接使用表单实现DELETE提交方式(注意:样式风格会改变)

    2. 方式二:使用超链接【a】实现DELETE提交方式

      • 使用Vue实现单击超链接,后提交对应表单

      • 取消超链接默认行为

      • 示例代码

        <div align="center" id="app">
            <a rel="nofollow" href="#" @click="deleteEmp">删除</a>
            <form id="delForm" th:action="@{/emps/}+${emp.id}" method="post">
                <input type="hidden" name="_method" value="DELETE">
            </form>
        </div>
        <script type="text/javascript" src="static/js/vue_v2.6.14.js"></script>
        <script type="text/javascript">
            new Vue({
                el:"#app",
                data:{},
                methods:{
                    deleteEmp(){
                        alert("hehe");
                        //获取响应表单
                        var formEle = document.getElementById("delForm");
                        formEle.submit();
                        //取消超链接默认行为
                        event.preventDefault();
                    }
                }
            });
        </script>
        
  • 实现修改功能

    1. 先获取原有的信息

    2. 在修改完后实现跳转

      <div  align="center">
          修改员工
          <form th:action="@{/emp}" method="post">
              <input type="hidden" name="_method" value="put">
              <input type="hidden" name="id" th:value="${employee.id}"><!-- 这里要将你要修改的员工id也要作为参数传到后端中 -->
              员工姓名:<input type="text" name="lastName" th:value="${employee.lastName}"/><br>
              员工邮箱:<input type="text" name="email" th:value="${employee.email}"/><br>
              员工性别:<input type="radio" name="gender" value="1" th:checked="${employee.gender == 1}"> 男
              <input type="radio" name="gender" value="0" th:checked="${employee.gender == 0}"> 女
              <br>
              员工部门: <select name="department.id">
              <option th:each="depart:${departs}"
                      th:value="${depart.id}"
                      th:text="${depart.departmentName}"
              th:selected="${depart.departmentName == employee.department.id}">
              </option>
          </select><br>
              <input type="submit" value="修改员工">
          </form>
      </div>
      

SpringMVC消息转换器

消息转化器概述

  • HttpMessageConverter<T>:消息转换器主要作用

    • 将java对象与请求报文及响应报文的相互转换

      image-20230107130227249

    • 使用HtpMessageConverter<T>将请求信息转化并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息,Spring 提供了两种途径: a)使用 @RequestBody / @ResponseBody 对处理方法进行标注。

      b)使用 HttpEntity<T>/ ResponseEntity<T> 作为处理方法的入参或返回值

使用消息转换器处理请求报文

  • 使用@RequsetBody获取请求体

    • 语法

      @Controller
      public class MessageConverterController {
          @PostMapping("/body")
          public String testBody(@RequestBody String resBody){
              System.out.println(resBody);
              return "success";
          }
      }
      

      注意:使用@RequestBody必须以POST方式提交,不能使用GET方式【GET提交方式,没有请求体】

  • 使用HttpEntity<T>对象,获取请求体及请求头

    • 语法

      @PostMapping("/HttpEntity")
          public String testHttpEntity(HttpEntity<String> httpEntity){
              HttpHeaders headers = httpEntity.getHeaders();
              System.out.println(headers);
              System.out.println("==========");
              String body = httpEntity.getBody();
              System.out.println(body);
              return SUCCESS;
          }
      

使用消息转换器处理响应报文

  • 使用@ResponseBody

    • 位置

      • 书写在类Class上面【当前类所有】
      • 书写在方法上面
    • 语法

      @GetMapping("/testResponse")
          @ResponseBody
          public String testResponse(){
              System.out.println("访问到了");
              return "访问成功";
          }
      
    • 作用:将指定的数据,直接以响应流的方式,响应数据

使用消息转换器处理json数据格式

使用步骤:

  • 导入相应jar包
<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.3</version>
        </dependency>
  • 装配MappingJackson2HttpMessageConverter消息转换器

    • 必须配置mvc:annotation-driver标签才能装配Jackson的转换器
  • 在需要转换ison数据的方法上,添加@ResponseBody需要被转换的数据作为方法的返回值

    @RequestMapping("/TestJson")
        @ResponseBody
        public Employee testJson(){
            System.out.println("处理json数据");
            Employee employee = new Employee(1010,"zs","zs@123",101);
            return employee;
        }
    
  • 底层实现原理【MappingJackson2HttpMessageConverter】

    • 添加jar包

    • 装配mvc:annotation-driver

    • 添加支持之前

      image-20230108101326591

    • 添加之后

      就会多出一个叫MappingJackson2HttpMessageConverter@4883的转换器

SpringMVC文件上传与文件下载

image-20230108102421295

文件下载

  • 实现文件下载的步骤

    • 准备文件下载的相关资源(放到WEB-INF目录下)

    • 将ResponseEntity<T>对象,作为方法返回值

    • 为ResponseEntity<T>对象,设置三个参数

    • 示例代码

      @Controller
      public class FileDownloadController {
      
          @RequestMapping("/Download")
          public ResponseEntity<byte[]> Download(String fileName, HttpServletRequest request){
              System.out.println("开始下载");
              ResponseEntity<byte[]> responseEntity = null;
              try {
                  ServletContext servletContext = request.getServletContext();
                  String Path = servletContext.getRealPath("/WEB-INF/download/" + fileName);
                  //创建输入流
                  InputStream is = new FileInputStream(Path);
                  //文件下载byte[]
                  byte[] bytes = new byte[is.available()];
                  is.read(bytes);
                  //设置响应头
                  HttpHeaders httpHeaders = new HttpHeaders();
                  //设置要下载的文件名字【及文件格式为附件格式,通知服务器下载当前资源,而不是打开】
                  httpHeaders.add("Content-Disposition","attachment;filename="+fileName);
                  //处理中文名的问题
                  httpHeaders.setContentDispositionFormData("attachment",new String(fileName.getBytes(StandardCharsets.UTF_8),"ISO-8859-1"));
                  //设置响应状态码
                  responseEntity = new ResponseEntity<>(bytes,httpHeaders, HttpStatus.OK);
              } catch (Exception e) {
                  e.printStackTrace();
              }
              return responseEntity;
          }
      }
      

文件的上传

  • 实现文件上传的思路

    • 准备工作

      • 准备文件上传页面
      • 表单的提交方式必须为POST
      • 设置表单enctype属性值为multipart/form-data
      • 表单中包含文件域[type=file]
    • 导入jar包

      <dependency>
      	<groupId>commons-fileupload</groupId>			
          <artifactId>commons-fileupload</artifactId>
      	<version>1.4</version>
      	</dependency>
      
    • 装配解析器: CommonsMultipartResolver

    • 注意:

      • id必须是multipartResolver
      • 设置上传文件字符集: defaultEncoding=UTF-8
      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
              <!--设置字符集-->
              <property name="defaultEncoding" value="UTF-8"/>
          </bean>
      
    • 实现步骤

      • 将type=file[文件域]直接入参: MultipartFile 类型即可
      • 获取文件名称
      • 获取上传文件真实路径
      • 实现文件上传即可
    • 示例代码

      @Controller
      public class FileUpload {
          @RequestMapping("/FileUpload")
          public String FileUpload(String username, MultipartFile uploadFile, HttpSession session){
              try {
                  //获取上传路径
                  String realPath = session.getServletContext().getRealPath("/WEB-INF/upLoad/");
                  //获取文件名称
                  String Filename = uploadFile.getOriginalFilename();
                  //检查文件是否存在
                  File file = new File(realPath);
                  if (!file.exists()){
                      file.mkdirs();
                  }
                  File realFile = new File(file + File.separator + Filename);
                  uploadFile.transferTo(realFile);
              } catch (IOException e) {
                  e.printStackTrace();
              }
              System.out.println(username+"上传了文件");
              return "success";
          }
      }
      
  • 文件上传的优化

    • 可以上传重复的文件

      • 通过文件名前加入UUID来解决【UUID(32位16进制来表示)全球唯一性】

        String uuid = UUID.randomUUID().toString().replace("-", "");
                    File realFile = new File(file + File.separator +uuid + Filename);
                    uploadFile.transferTo(realFile);
        
      • 时间戳来解决

    • 限制上传文件的大小

      • 在装配CommonsMultipartResolver时,设置上传文件的上限

        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
                <!--设置字符集-->
                <property name="defaultEncoding" value="UTF-8"/>
                <property name="maxUploadSizePerFile" value="10240"/>
            </bean>
        

SpringMVC中拦截器【Interceptor】

拦截器与过滤器区别

  • 过滤器【Filter】属于web服务器组件
    • 过滤器主要作用:过滤Servlet请求
    • 执行时机:两处执行时机【Servlet前,Servlet后】
  • 拦截器【Interceptor】属于框架【SpringMVC】
    • 拦截器主要作用:拦截Controller请求
    • 执行时机:三处执行时机
      1. 执行DispatcherServelt之后,Controller之前
      2. 执行Controller之后,DispatcherServlet之前
      3. 执行DispatcherServlet之后【渲染视图之后】

image-20230108130554510

拦截器概述

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

实现拦截器步骤

  • 实现接口:HandlerInterceptor

  • 重写三个方法

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

        <mvc:interceptors>
            <ref bean="myInterceptor"/><!-- 默认全局都会进行拦截 -->
        </mvc:interceptors>
    <!-- 局部配置 -->
    <mvc:interceptors>
            <mvc:interceptor>
                <mvc:mapping path="/TestJson"/>
                <ref bean="myInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>
    
  • 示例代码

@Component
public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("MyInterceptor====>preHandle");
        return true;
    }


    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                            @Nullable ModelAndView modelAndView) throws Exception {
        System.out.println("MyInterceptor====>postHandle");
    }


   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                 @Nullable Exception ex) throws Exception {
       System.out.println("MyInterceptor====>afterCompletion");
    }
}

拦截器工作原理

  • 单个拦截器工作原理
    • 浏览器向服务器发送请求
    • 执行拦截器第一个方法preHandle()
    • 执行Controller中方法,处理请求做出响应
    • 执行拦截器第二个方法postHandle()
    • 执行DispatcherServlet中渲染视图
    • 执行拦截器第三个方法afterCompletion()
    • 响应
  • 多个拦截器工作原理
    • 浏览器向服务器发送请求
    • 执行拦截器1第一个方法preHandle()
    • 执行拦截器2第一个方法preHandle()
    • 执行Controller中方法,处理请求做出响应
    • 执行拦截器2第二个方法postHandle()
    • 执行拦截器1第二个方法postHandle()
    • 执行DispatcherServlet中渲染视图
    • 执行拦截器2第三个方法afterCompletion()
    • 执行拦截器1第三个方法afterCompletion()
    • 响应

拦截器的顺序由配置的顺序决定

拦截器preHandle()方法返回值

  • 当第一个拦截器preHandle()方法返回false时,执行当前方法后,程序终止

    image-20230109102952715

    image-20230109103058371

    及不会执行后续方法

    image-20230109103620152

  • 当不是第一个拦截器preHandle0方法返回false时

    • 执行当前拦截器及之前拦截器的preHandle()方法。执行之前拦截器的afterCompletion0方法

SpringMVC异常处理器

为什么要处理异常

  • 如程序中出现异常未处理,会导致程序运行终止【岩机】
    • JavaSE阶段异常处理机制 try-catch-finally
    • throw或throws

SpringMVC中异常处理器

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

  • 需要掌握两个异常处理器实现类

    • DefaultHandleExceptionResolver:默认异常处理器,默认开启,可以支持10+多异常处理
    • SimpleMappingExceptionResolver
      • 映射自定义异常处理器,作用:将指定的异常映射到指定的页面
      • 装配异常处理器【SimpleMappingExceptionResolver】
  • 总结

    • 出现异常,不会执行postHandle()

      image-20230109113541813

    • 出现异常,也会返回ModelAndview

      image-20230109113757209

SpringMVC工作原理

扩展三个对象

  • HandlerMapping(mapping)

    • 概述:请求处理器映射器对象

    • 作用: 通过HandlerMapping可以获取HandlerExecutionChain对象

    • 源码

      //源码
      /*Interface to be implemented by objects that define a mapping between requests and handler objects.*/
      //简易理解
      //HandlerMapping定义一个映射关系,所有请求与请求处理器的映射关系
      
  • HandlerExecutionChain(mappedHandler)

    • 概述:请求处理器执行链对象

    • 作用: 通过HandlerExecutionChain对象可以获取HandlerAdapter对象

    • 源码

      //源码
      /* Handler execution chain, consisting of handler object and any handler
      interceptors .
      Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.*/
      
      //自己理解
      //请求处理器执行链对象,由当前请求处理器[Controller] 和对应拦截器[Interceptors]组成
      
  • HandlerAdapter(ha)

    • 概述:请求处理器适配器对象
    • 作用:通过HandlerAdapter的ha.handle0调用请求处理器中相应方法

SpringMVC工作原理【URL不存在】

  1. 请求【浏览器向服务器发送请求,携带URL(/testSrpingMVCWorking)】
  2. 通过DispatcherServlet加载SpringMVC容器对象,从而加载Controller【请求处理器】
  3. 判断URL是否存在
    • 不存在:判断是否配置mvc:default-servlet-handler/
      • 配置:出现404现象:同时提示URL不可用(他就会主动的去找资源,没有配置就不会)
      • 未配置:出现404现象,但不会提示

springMVC工作原理【URL存在】

  1. 请求【浏览器向服务器发送请求,携带URL(/testSrpingMVCWorking)】

  2. 通过DispatcherServlet加载SpringMVC容器对象,从而加载Controller【请求处理器】

    • 加载三个对象【HandlerMapping、HandlerExecutionChain、HandlerAdapter】
  3. 判断URL是否存在【存在】

  4. 执行Interceptor【拦截器】第一个方法【preHandle()】

    //Dispatcherservlet的1056行代码
    if (!mappedHandler.applyPreHandle(processedRequest,response)){
        return;
    }
    
  5. 执行Controller【请求处理器】中的相应方法【处理请求,做出响应】

    //Dispatcherservlet的1061
    // Actua1ly invoke the handler.
    mv = ha.handle(processedRequest,response, mappedHandler.getHandler());
    
  6. 判断是否存在异常

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

    //Dispatcherservlet的1435行代码
    if (this.viewResolvers != nu11){
    	for (ViewResolver viewResolver : this.viewResolvers) {
    	View view = viewResolver.resolveviewName(viewName, 1ocale);
    	if (view != nu11) {
    		return view;
    	}
    } 
    
  8. View对象开始渲染视图

    • 将数据共享
    • 路径跳转
  9. 执行拦截器第三个方法【afterCompletion()】

    //Dispatcherservlet的1157行代码
    if (mappedHandler != nu11) {
    //Exception (if any) is already handled..
    mappedHandler.triggerAfterCompletion(request,response,null);
    }
    
  10. 响应

  • 请求,通过DispatcherServelt加载到SpringMVC容器对象,并加载三个对象【HandlerMapping,HandlerExecutionChain,HandlerAdapter】

  • 判断URL是否存在

    • 存在
      • 执行Interceptor【拦截器】第一个方法【preHandle()】
      • 执行Controller【请求处理器】中的相应方法【处理请求,做出响应】
      • 判断是否存在异常
        • 存在异常
          • 通过HandlerExceptionResolver异常处理器处理异常,并返回ModelAndView
        • 不存在异常
          • Controller返回ModelAndView
          • 触发拦截器第二个方法[postHandle()]
      • 通过ViewResolver【视图解析器对象】将View【视图对象】 从ModelAndView中解析出来
      • View对象开始渲染视图
      • 执行拦截器第三个方法【afterCompletion()】
    • 不存在
      • 判断是否配置mvc:default-servlet-handler/
        • 配置:出现404现象:同时提示URL不可用(他就会主动的去找资源,没有配置就不会)
        • 未配置:出现404现象,但不会提示
  • 响应

    image-20230109132958945

SSM【Spring+SpringMVC+Mybatis】整合

SSM整合思路

  • Spring+SpringMVC
    • 容器对象的管理问题
      • SpringMVC容器对象,由DispatcherSerlet管理
      • Spring容器对象,由ContextLoaderListener管理
    • 解决组件扫描的冲突问题
      • SpringMVC只扫描Controller层
      • Spring扫描排除Controller层
  • Spring+Mybatis
    • 关于数据源、事务管理的代码冲突问题
      • 统一交给Spring管理
    • Spring管理Mybatis核心对象
      • SqlsessionFactory
      • Mapper代理对象

SSM整合步骤

  • Spring+SpringMVC

    • 导入jar包

      <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.13.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, 解决请求乱码问题

          <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>forceRequestEncoding</param-name>
                  <param-value>true</param-value>
              </init-param>
          </filter>
          
        • 注册HiddenHttpMethodFilter,支持PUT&DELETE提交【REST风格】

          <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>
          
        • 注册DispatcherServlet【前端控制器】,管理springMVC容器对象

          <servlet>
                  <servlet-name>DispatcherServlet</servlet-name>
                  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                  <init-param>
                      <param-name>contextConfigLocation</param-name>
                      <param-value>classpath:springmvc.xml</param-value>
                  </init-param>
                  <load-on-startup>1</load-on-startup>
              </servlet>
              <servlet-mapping>
                  <servlet-name>DispatcherServlet</servlet-name>
                  <url-pattern>/</url-pattern>
              </servlet-mapping>
          
        • 注册一个上下文参数【contextConfigLocation】,设置spring.xml配置文件路径

          <context-param>
                  <param-name>contextConfigLocation</param-name>
                  <param-value>classpath:spring.xml</param-value>
              </context-param>
          
        • 注册ContextLoaderListener,管理spring容器对象

          <listener>
                  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
           </listener>
          
      • springMVC.xml

        • 开启组件扫描【只扫描Controller】

              <context:component-scan base-package="ssm">
                  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
              </context:component-scan>
          
        • 装配视图解析器

          <bean class="org.thymeleaf.spring5.view.ThymeleafViewResolver" id="viewResolver">
              <property name="characterEncoding" value="UTF-8"/>
              <property name="templateEngine">
                  <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                      <property name="templateResolver">
                          <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                              <property name="characterEncoding" value="UTF-8"/>
                              <property name="prefix" value="/WEB-INF/pages/"/>
                              <property name="suffix" value=".html"/>
                          </bean>
                      </property>
                  </bean>
              </property>
          </bean>
          
        • 装配视图控制器[view-controller]

          <mvc:view-controller path="/" view-name="index"/>
          
        • 装配default-servlet-handler,解决静态资源加载问题

          <mvc:default-servlet-handler/>
          
        • 装配annotation-driven,解决后续问题

          • 解决view-controller问题

          • 解决default-servlet-handler问题

          • 解决jackson装配消息转换器问题[等23+种]

            <mvc:annotation-driven/>
            
      • spring.xml

        • 开启组件扫描【排除Controller】

          <contxext:component-scan base-package="ssm">
                  <contxext:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
              </contxext:component-scan>
          
  • Spring+Mybatis

    • 导入jar包

      • spring的jar包

        		<dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-orm</artifactId>
                    <version>5.3.1</version>
                </dependency>
        <!--        因为orm这个包依赖jdbc所以他会自动装配,我们就不需要在用jdbc这个坐标-->
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-jdbc</artifactId>
                    <version>5.3.1</version>
                </dependency>
                <dependency>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aspects</artifactId>
                    <version>5.3.1</version>
                </dependency>
        
      
      
    • mybatis的jar包

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.10</version>
      </dependency>
      <!--导入MyBatis的jar包-->
      <dependency>
          <groupId>org.mybatis</groupId>
          <artifactId>mybatis</artifactId>
          <version>3.5.6</version>
      </dependency>
      <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.26</version>
      </dependency>
      <!-- pagehelper -->
      <dependency>
          <groupId>com.github.pagehelper</groupId>
          <artifactId>pagehelper</artifactId>
          <version>5.0.0</version>
      </dependency>
      
    • spring与mybatis整合jar包

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

    • spring.xml

      • 开启组件扫描【排除Controller层】

      • 加载外部属性文件

      • 装配数据源【DruidDataSource】

        <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
                <property name="driverClassName" value="${db.driverClassName}"/>
                <property name="url" value="${db.url}"/>
                <property name="username" value="${db.username}"/>
                <property name="password" value="${db.password}"/>
            </bean>
        
      • 装配事务管理器【DataSourceTransactionManager】

        <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
        
      • 开启声明式事务管理注解支持

        <tx:annotation-driven transaction-manager="transactionManager"/>
        
      • 装配SqlSessionFactoryBean,管理SqlSessionFactory

            <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="sessionFactoryBean">
        <!--        设置数据源-->
                <property name="dataSource" ref="dataSource"/>
        <!--        配置mybatis-config.xml核心配置文件路径-->
                <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <!--        设置类别名-->
                <property name="typeAliases" value="ssm.pojo"/>
        <!--        配置映射文件加载路径-->
                <property name="mapperLocations" value="classpath:mapper/*.xml"/>
            </bean>
        
      • 装配MapperScannerConfigurer,管理Mapper代理对象

        <mybatis-spring:scan base-package="ssm.mapper"/>
        
    • mybatis-config.xml【核心配置文件】

      • 设置别名

      • 开启驼峰式命名映射设置

        <settings>
                <setting name="aggressiveLazyLoading" value="true"/>
                <setting name="lazyLoadingEnabled" value="false"/>
                <setting name="mapUnderscoreToCamelCase" value="true"/>
                <setting name="cacheEnabled" value="true"/>
            </settings>
        
      • PageHelper分页插件

    • xxxMapper.xml【映射文件】

举报

相关推荐

0 条评论