• SpringMVC学习笔记(三)


    十三、注解配置 SpringMVC

    使用配置类和注解代替web.xml和SpringMVC配置文件的功能

    13.1 创建初始化类,代替 web.xml

    ​ 在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。 Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实WebApplicationInitializer的类并将配置的任务交给它们来完成。

    ​ Spring3.2引入了一个便利的WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatcherServletInitializer,当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。

    public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
        @Override
        //设置一个配置类代替Spring的配置文件
        protected Class<?>[] getRootConfigClasses() {
            return new Class[]{SpringConfig.class};
        }
    
        @Override
        //设置一个配置类代替SpringMVC的配置文件
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{WebConfig.class};
        }
    
        @Override
        //设置SpringMVC的前端控制器DispatcherServlet的url-pattern
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        @Override
        //设置当前的过滤器
        protected Filter[] getServletFilters() {
            //创建编码过滤器
            CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
            characterEncodingFilter.setEncoding("UTF-8");
            characterEncodingFilter.setForceEncoding(true);
            //创建处理请求方式的过滤器
            HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
            return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    13.2 创建SpringConfig配置类,代替spring的配置文件

    @Configuration 
    public class SpringConfig 
    { //ssm整合之后,spring的配置信息写在此类中 }
    
    • 1
    • 2
    • 3

    13.3 创建WebConfig配置类,代替SpringMVC的配置文件

    //将类标识为配置类
    @Configuration
    //扫描组件
    @ComponentScan("com.atguigu.controller")
    //开启mvc的注解驱动
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        //默认的servlet处理静态资源
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    
        @Override
        //配置视图解析器
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/").setViewName("index");
        }
    
        //@Bean注解可以将标识的方法的返回值作为bean进行管理,bean的id为方法的方法名
        @Bean
        public CommonsMultipartResolver multipartResolver(){
            return new CommonsMultipartResolver();
        }
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            FirstInterceptor firstInterceptor = new FirstInterceptor();
            registry.addInterceptor(firstInterceptor).addPathPatterns("/**");
        }
    
        @Override
        //配置异常解析器
        public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
            SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
            Properties prop = new Properties();
            prop.setProperty("java.lang.ArithmeticException", "error");
            exceptionResolver.setExceptionMappings(prop);
            exceptionResolver.setExceptionAttribute("ex");
            resolvers.add(exceptionResolver);
        }
    
        //配置生成模板解析器
        @Bean
        public ITemplateResolver templateResolver() {
            WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
            // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
            ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
                    webApplicationContext.getServletContext());
            templateResolver.setPrefix("/WEB-INF/templates/");
            templateResolver.setSuffix(".html");
            templateResolver.setCharacterEncoding("UTF-8");
            templateResolver.setTemplateMode(TemplateMode.HTML);
            return templateResolver;
        }
    
        //生成模板引擎并为模板引擎注入模板解析器
        @Bean
        public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
            SpringTemplateEngine templateEngine = new SpringTemplateEngine();
            templateEngine.setTemplateResolver(templateResolver);
            return templateEngine;
        }
    
        //生成视图解析器并未解析器注入模板引擎
        @Bean
        public ViewResolver viewResolver(SpringTemplateEngine templateEngine) {
            ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
            viewResolver.setCharacterEncoding("UTF-8");
            viewResolver.setTemplateEngine(templateEngine);
            return viewResolver;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    13.4 测试功能

    @RequestMapping("/") 
    public String index(){ return "index"; }
    
    • 1
    • 2

    十四、SpringMVC 执行流程

    14.1 SpringMVC 常用组件

    • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供;作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求
    • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供;作用:根据请求的url、method等信息查找Handler,即控制器方法
    • Handler:处理器,需要工程师开发;作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理
    • HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供;作用:通过HandlerAdapter对处理器(控制器方法)进行执行
    • ViewResolver:视图解析器,不需要工程师开发,由框架提供;作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView
    • View:视图;作用:将模型数据通过页面展示给用户

    14.2 DispatcherServlet 初始化过程

    ​ DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。

    在这里插入图片描述

    ①初始化 WebApplicationContext

    所在类:org.springframework.web.servlet.FrameworkServlet

    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        WebApplicationContext wac = null;
        if (this.webApplicationContext != null) {
          wac = this.webApplicationContext;
          if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)wac;
            if (!cwac.isActive()) {
              if (cwac.getParent() == null) {
                cwac.setParent(rootContext);
              }
    
              this.configureAndRefreshWebApplicationContext(cwac);
            }
          }
        }
    
        if (wac == null) {
          wac = this.findWebApplicationContext();
        }
    
        if (wac == null) {
          wac = this.createWebApplicationContext(rootContext);
        }
    
        if (!this.refreshEventReceived) {
          synchronized(this.onRefreshMonitor) {
            this.onRefresh(wac);
          }
        }
    
        if (this.publishContext) {
          String attrName = this.getServletContextAttributeName();
          this.getServletContext().setAttribute(attrName, wac);
        }
    
        return wac;
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    ②创建 WebApplicationContext

    所在类:org.springframework.web.servlet.FrameworkServlet

    protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
        Class<?> contextClass = this.getContextClass();
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
          throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
        } else {
          ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
          wac.setEnvironment(this.getEnvironment());
          wac.setParent(parent);
          String configLocation = this.getContextConfigLocation();
          if (configLocation != null) {
            wac.setConfigLocation(configLocation);
          }
    
          this.configureAndRefreshWebApplicationContext(wac);
          return wac;
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    DispatcherServlet 初始化策略

    FrameworkServlet创建WebApplicationContext后,刷新容器,调用onRefresh(wac),此方法在DispatcherServlet中进行了重写,调用了initStrategies(context)方法,初始化策略,即初始化DispatcherServlet的各个组件

    所在类:org.springframework.web.servlet.DispatcherServlet

    protected void initStrategies(ApplicationContext context) {
        this.initMultipartResolver(context);
        this.initLocaleResolver(context);
        this.initThemeResolver(context);
        this.initHandlerMappings(context);
        this.initHandlerAdapters(context);
        this.initHandlerExceptionResolvers(context);
        this.initRequestToViewNameTranslator(context);
        this.initViewResolvers(context);
        this.initFlashMapManager(context);
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    14.3 DispatcherServlet 调用组件处理请求

    processRequest()

    FrameworkServlet重写HttpServlet中的service()和doXxx(),这些方法中调用了processRequest(request, response)

    所在类:org.springframework.web.servlet.FrameworkServlet

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        LocaleContext localeContext = this.buildLocaleContext(request);
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
        this.initContextHolders(request, localeContext, requestAttributes);
    
        try {
          this.doService(request, response);
        } catch (IOException | ServletException var16) {
          failureCause = var16;
          throw var16;
        } catch (Throwable var17) {
          failureCause = var17;
          throw new NestedServletException("Request processing failed", var17);
        } finally {
          this.resetContextHolders(request, previousLocaleContext, previousAttributes);
          if (requestAttributes != null) {
            requestAttributes.requestCompleted();
          }
    
          this.logResult(request, response, (Throwable)failureCause, asyncManager);
          this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    doService()

    所在类:org.springframework.web.servlet.DispatcherServlet

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        this.logRequest(request);
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
          attributesSnapshot = new HashMap();
          Enumeration attrNames = request.getAttributeNames();
    
          label120:
          while(true) {
            String attrName;
            do {
              if (!attrNames.hasMoreElements()) {
                break label120;
              }
    
              attrName = (String)attrNames.nextElement();
            } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
    
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
          }
        }
    
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
        if (this.flashMapManager != null) {
          FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
          if (inputFlashMap != null) {
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
          }
    
          request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
          request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
        }
    
        RequestPath requestPath = null;
        if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
          requestPath = ServletRequestPathUtils.parseAndCache(request);
        }
    
        try {
          this.doDispatch(request, response);
        } finally {
          if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
            this.restoreAttributesAfterInclude(request, attributesSnapshot);
          }
    
          if (requestPath != null) {
            ServletRequestPathUtils.clearParsedRequestPath(request);
          }
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    doDispatch()

    所在类:org.springframework.web.servlet.DispatcherServlet

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
        try {
          try {
            ModelAndView mv = null;
            Object dispatchException = null;
    
            try {
              processedRequest = this.checkMultipart(request);
              multipartRequestParsed = processedRequest != request;
              mappedHandler = this.getHandler(processedRequest);
              if (mappedHandler == null) {
                this.noHandlerFound(processedRequest, response);
                return;
              }
    
              HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
              String method = request.getMethod();
              boolean isGet = "GET".equals(method);
              if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
                  return;
                }
              }
    
              if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
              }
    
              mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
              if (asyncManager.isConcurrentHandlingStarted()) {
                return;
              }
    
              this.applyDefaultViewName(processedRequest, mv);
              mappedHandler.applyPostHandle(processedRequest, response, mv);
            } catch (Exception var20) {
              dispatchException = var20;
            } catch (Throwable var21) {
              dispatchException = new NestedServletException("Handler dispatch failed", var21);
            }
    
            this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
          } catch (Exception var22) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
          } catch (Throwable var23) {
            this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
          }
    
        } finally {
          if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
              mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
          } else if (multipartRequestParsed) {
            this.cleanupMultipart(processedRequest);
          }
    
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    processDispatchResult()

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
        boolean errorView = false;
        if (exception != null) {
          if (exception instanceof ModelAndViewDefiningException) {
            this.logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException)exception).getModelAndView();
          } else {
            Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
            mv = this.processHandlerException(request, response, handler, exception);
            errorView = mv != null;
          }
        }
    
        if (mv != null && !mv.wasCleared()) {
          this.render(mv, request, response);
          if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
          }
        } else if (this.logger.isTraceEnabled()) {
          this.logger.trace("No view rendering, null ModelAndView returned.");
        }
    
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
          if (mappedHandler != null) {
            mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
          }
    
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    14.4 SpringMVC 的执行流程

    1. 用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获

    2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI),判断请求URI对应的映射

      • 不存在

        • 再判断是否配置了mvc:default-servlet-handler

        • 如果没配置,则控制台报映射查找不到,客户端展示404错误

          在这里插入图片描述

        • 如果有配置,则访问目标资源(一般为静态资源,如:JS,CSS,HTML),找不到客户端也会展示404错误

          在这里插入图片描述

      • 存在则执行下面的流程

    3. 根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain执行链对象的形式返回

    4. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。

    5. 如果成功获得HandlerAdapter,此时将开始执行拦截器的preHandler(…)方法【正向】

    6. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

      • HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
      • 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
      • 数据格式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
      • 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
    7. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象。

    8. 此时将开始执行拦截器的postHandle(…)方法【逆向】。

    9. 根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver进行视图解析,根据Model和View,来渲染视图。

    10. 渲染视图完毕执行拦截器的afterCompletion(…)方法【逆向】。

    11. 将渲染结果返回给客户端。

    十五、SSM 整合

    15.1 ContextLoaderListener

    Spring提供了监听器ContextLoaderListener,实现ServletContextListener接口,可监听ServletContext的状态,在web服务器的启动,读取Spring的配置文件,创建Spring的IOC容器。web应用中必须在web.xml中配置

    <listener> 
     
    <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class> 
    listener> 
     
    <context-param> 
        <param-name>contextConfigLocationparam-name> 
        <param-value>classpath:spring.xmlparam-value> 
    context-param>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    15.2 准备工作

    ①创建 Maven Module

    ②导入依赖

    
    <project xmlns="http://maven.apache.org/POM/4.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0modelVersion>
    
      <groupId>com.cgg.ssmgroupId>
      <artifactId>ssmartifactId>
      <version>1.0-SNAPSHOTversion>
      <packaging>warpackaging>
    
      <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
        <spring.version>5.3.1spring.version>
      properties>
    
    
      <dependencies>
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-contextartifactId>
          <version>${spring.version}version>
        dependency>
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-beansartifactId>
          <version>${spring.version}version>
        dependency>
        
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-webartifactId>
          <version>${spring.version}version>
        dependency>
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-webmvcartifactId>
          <version>${spring.version}version>
        dependency>
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-jdbcartifactId>
          <version>${spring.version}version>
        dependency>
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-aspectsartifactId>
          <version>${spring.version}version>
        dependency>
        <dependency>
          <groupId>org.springframeworkgroupId>
          <artifactId>spring-testartifactId>
          <version>${spring.version}version>
        dependency>
        
        <dependency>
          <groupId>org.mybatisgroupId>
          <artifactId>mybatisartifactId>
          <version>3.5.7version>
        dependency>
        
        <dependency>
          <groupId>org.mybatisgroupId>
          <artifactId>mybatis-springartifactId>
          <version>2.0.6version>
        dependency>
        
        <dependency>
          <groupId>com.alibabagroupId>
          <artifactId>druidartifactId>
          <version>1.0.9version>
        dependency>
        
        <dependency>
          <groupId>junitgroupId>
          <artifactId>junitartifactId>
          <version>4.12version>
          <scope>testscope>
        dependency>
        
        <dependency>
          <groupId>mysqlgroupId>
          <artifactId>mysql-connector-javaartifactId>
          <version>8.0.16version>
        dependency>
        
        <dependency>
          <groupId>log4jgroupId>
          <artifactId>log4jartifactId>
          <version>1.2.17version>
        dependency>
        
        <dependency>
          <groupId>com.github.pagehelpergroupId>
          <artifactId>pagehelperartifactId>
          <version>5.2.0version>
        dependency>
        
        <dependency>
          <groupId>ch.qos.logbackgroupId>
          <artifactId>logback-classicartifactId>
          <version>1.2.3version>
        dependency>
        
        <dependency>
          <groupId>javax.servletgroupId>
          <artifactId>javax.servlet-apiartifactId>
          <version>3.1.0version>
          <scope>providedscope>
        dependency>
        <dependency>
          <groupId>com.fasterxml.jackson.coregroupId>
          <artifactId>jackson-databindartifactId>
          <version>2.12.1version>
        dependency>
        <dependency>
          <groupId>commons-fileuploadgroupId>
          <artifactId>commons-fileuploadartifactId>
          <version>1.3.1version>
        dependency>
        
        <dependency>
          <groupId>org.thymeleafgroupId>
          <artifactId>thymeleaf-spring5artifactId>
          <version>3.0.12.RELEASEversion>
        dependency>
      dependencies>
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129

    ③创建表

    CREATE TABLE `t_emp` ( 
    `emp_id` int(11) NOT NULL AUTO_INCREMENT, 
    `emp_name` varchar(20) DEFAULT NULL, 
    `age` int(11) DEFAULT NULL, 
    `sex` char(1) DEFAULT NULL, 
    `email` varchar(50) DEFAULT NULL, 
    PRIMARY KEY (`emp_id`) 
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    15.3 配置 web.xml

    
      <filter>
        <filter-name>CharacterEncodingFilterfilter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilterfilter-class>
        <init-param>
          <param-name>encodingparam-name>
          <param-value>UTF-8param-value>
        init-param>
        <init-param>
          <param-name>forceEncodingparam-name>
          <param-value>trueparam-value>
        init-param>
      filter>
      <filter-mapping>
        <filter-name>CharacterEncodingFilterfilter-name>
        <url-pattern>/*url-pattern>
      filter-mapping>
    
      
      <filter>
        <filter-name>HiddenHttpMethodFilterfilter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilterfilter-class>
      filter>
      <filter-mapping>
        <filter-name>HiddenHttpMethodFilterfilter-name>
        <url-pattern>/*url-pattern>
      filter-mapping>
    
      
      <servlet>
        <servlet-name>SpringMVCservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        
        <init-param>
          <param-name>contextConfigLocationparam-name>
          <param-value>classpath:springmvc.xmlparam-value>
        init-param>
        
        <load-on-startup>1load-on-startup>
      servlet>
      <servlet-mapping>
        <servlet-name>SpringMVCservlet-name>
        <url-pattern>/url-pattern>
      servlet-mapping>
    
      
      <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
      listener>
    
      
      <context-param>
        <param-name>contextConfigLocationparam-name>
        <param-value>classpath:spring.xmlparam-value>
      context-param>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    15.4 创建 SpringMVC 的配置文件并配置

    
      <context:component-scan base-package="com.cgg.ssm.Controller">context:component-scan>
    
      
      <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <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="prefix" value="/WEB-INF/templates/"/>
                
                <property name="suffix" value=".html"/>
                <property name="templateMode" value="HTML5"/>
                <property name="characterEncoding" value="UTF-8" />
              bean>
            property>
          bean>
        property>
      bean>
    
      
      <mvc:default-servlet-handler />
    
      
      <mvc:annotation-driven />
    
      
      <mvc:view-controller path="/" view-name="index">mvc:view-controller>
    
      
      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">bean>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    15.5 搭建 MyBatis 环境

    ①创建属性文件 jdbc.properties

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/ssm
    jdbc.username=root
    jdbc.password=123456
    
    • 1
    • 2
    • 3
    • 4

    ②创建 MyBatis 的核心配置文件 mybatis-config.xml

    
    DOCTYPE configuration
      PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
      <settings>
        
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        
        <setting name="mapUnderscoreToCamelCase" value="true"/>
      settings>
    
      <plugins>
        
        <plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
      plugins>
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    ③创建 Mapper 接口和映射文件

    public interface EmployeeMapper {
      public List<Employee> getAllEmployee();
    }
    <mapper namespace="com.cgg.ssm.mapper.EmployeeMapper">
      <!--填写映射-->
    <!--  public List<Employee> getAllEmployee();-->
      <select id="getAllEmployee" resultType="Employee">
        select * from t_emp
      </select>
    </mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    ④创建日志文件 log4j.xml

    
    DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    
        <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
            <param name="Encoding" value="UTF-8" />
            <layout class="org.apache.log4j.PatternLayout">
                <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m  (%F:%L) \n" />
            layout>
        appender>
        <logger name="java.sql">
            <level value="debug" />
        logger>
        <logger name="org.apache.ibatis">
            <level value="info" />
        logger>
        <root>
            <level value="debug" />
            <appender-ref ref="STDOUT" />
        root>
    log4j:configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    15.6 创建 Spring 的配置文件并配置

    
    <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xmlns:tx="http://www.springframework.org/schema/tx"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    
      
      <context:component-scan base-package="com.cgg.ssm">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
      context:component-scan>
    
      
      <context:property-placeholder location="classpath:jdbc.properties">context:property-placeholder>
    
      
      <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}">property>
        <property name="url" value="${jdbc.url}">property>
        <property name="username" value="${jdbc.username}">property>
        <property name="password" value="${jdbc.password}">property>
      bean>
    
      
      <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource">property>
      bean>
    
      
      <tx:annotation-driven transaction-manager="transactionManager">tx:annotation-driven>
    
      
      <bean class="org.mybatis.spring.SqlSessionFactoryBean">
        
        <property name="configLocation" value="classpath:mybatis-config.xml">property>
        
        <property name="dataSource" ref="dataSource">property>
        
        <property name="typeAliasesPackage" value="com.cgg.ssm.pojo">property>
        
        
      bean>
    
      
      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.cgg.ssm.mapper">property>
      bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    15.7 测试功能

    ①创建组件

    实体类Employee

    public class Employee {
    
        private Integer empId;
    
        private String empName;
    
        private Integer age;
    
        private String gender;
    
        private String email;
    
        public Employee() {
        }
    
        public Employee(Integer empId, String empName, Integer age, String gender, String email) {
            this.empId = empId;
            this.empName = empName;
            this.age = age;
            this.gender = gender;
            this.email = email;
        }
    
        public Integer getEmpId() {
            return empId;
        }
    
        public void setEmpId(Integer empId) {
            this.empId = empId;
        }
    
        public String getEmpName() {
            return empName;
        }
    
        public void setEmpName(String empName) {
            this.empName = empName;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        @Override
        public String toString() {
            return "Employee{" +
                    "empId=" + empId +
                    ", empName='" + empName + '\'' +
                    ", age=" + age +
                    ", gender='" + gender + '\'' +
                    ", email='" + email + '\'' +
                    '}';
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74

    创建控制层组件EmployeeController

    @Controller
    public class EmployeeController {
    
      @Autowired
      private EmployeeService employeeService;
    
      @RequestMapping(value = "/employee",method = RequestMethod.GET)
      public String getAllEmployee(Model model){
        List<Employee> list = employeeService.getAllEmployee();
        System.out.println("EmployeeController................");
        model.addAttribute("list", list);
        return "employ_list";
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    创建接口EmployeeService

    public interface EmployeeService { PageInfo<Employee> getEmployeeList(Integer pageNum); }
    
    • 1

    创建实现类EmployeeServiceImpl

    @Controller
    public class EmployeeController {
    
      @Autowired
      private EmployeeService employeeService;
    ///employee/page/1
      @RequestMapping(value = "/employee/page/{pageNum}",method = RequestMethod.GET)
      public String getEmployeePage(@PathVariable("pageNum") Integer pageNum,Model model){
        PageInfo<Employee> page = employeeService.getEmployeePage(pageNum);
        model.addAttribute("page", page);
        return "employ_list";
      }
    
      @RequestMapping(value = "/employee",method = RequestMethod.GET)
      public String getAllEmployee(Model model){
        List<Employee> list = employeeService.getAllEmployee();
        System.out.println("EmployeeController................");
        model.addAttribute("list", list);
        return "employ_list";
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    ②创建页面

    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
      <meta charset="UTF-8">
      <title>员工列表title>
      <link rel="stylesheet" th:href="@{/static/css/index_work.css}">
    head>
    <body>
    <table>
      <tr>
        <th colspan="6">员工列表th>
      tr>
      <tr>
        <th>流水号th>
        <th>员工姓名th>
        <th>年龄th>
        <th>性别th>
        <th>邮箱th>
        <th>操作th>
      tr>
      <tr th:each="employee,status : ${page.list}">
        <td th:text="${status.count}">td>
        <td th:text="${employee.empName}">td>
        <td th:text="${employee.age}">td>
        <td th:text="${employee.gender}">td>
        <td th:text="${employee.email}">td>
        <td>
          <a href="">删除a>
          <a href="">修改a>
        td>
      tr>
    table>
    <div style="text-align: center;">
      <a th:if="${page.hasPreviousPage}" th:href="@{/employee/page/1}">首页a>
      <a th:if="${page.hasPreviousPage}" th:href="@{'/employee/page/'+${page.prePage}}">上一页a>
      <span th:each="num : ${page.navigatepageNums}">
            <a th:if="${page.pageNum == num}" style="color: red;" th:href="@{'/employee/page/'+${num}}" th:text="'['+${num}+']'">a>
            <a th:if="${page.pageNum != num}" th:href="@{'/employee/page/'+${num}}" th:text="${num}">a>
        span>
      <a th:if="${page.hasNextPage}" th:href="@{'/employee/page/'+${page.nextPage}}">下一页a>
      <a th:if="${page.hasNextPage}" th:href="@{'/employee/page/'+${page.pages}}">末页a>
    div>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    ③访问测试分页功能

    localhost:8080/employee/page/1

  • 相关阅读:
    儿童医疗保健生物识别技术市场现状及未来发展趋势分析
    LeetCode-637. Average of Levels in Binary Tree [C++][Java]
    代码随想录52——动态规划:300最长递增子序列、674最长连续递增序列、 718最长重复子数组
    【电路笔记】-波特图(Bode Diagrams)
    Spring面试大全——(有这一篇就够了)
    STM32开发——感应垃圾桶(舵机、超声波测距、振动检测)
    感悟2022年:玫琳凯公布今年上半年以来的奖项、里程碑和成就
    docker load and build过程的一些步骤理解
    《Go Web 编程》之第6章 存储数据
    golang 协程的实现原理
  • 原文地址:https://blog.csdn.net/weixin_42200347/article/details/126456382