SSM-SpringMVC(五)-纯注解整合SSM

用Initializer取代web.xml

  1. 删除web.xml新建一个WebInitializer类,并实现AbstractAnnotationConfigDispatcherServletInitializer接口

     //com.zh.cfg.WebInitializer
     public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
         /**
          * 父容器的配置类
          */
         @Override
         protected Class<?>[] getRootConfigClasses() {
             return new Class[]{SpringConfig.class};
         }
            
         /**
          * 子容器的配置类(SpringMVC相关的配置类)
          */
         @Override
         protected Class<?>[] getServletConfigClasses() {
             return new Class[]{SpringMVCConfig.class};
         }
            
         /**
          * 配置DispatcherServlet的url-pattern
          */
         @Override
         protected String[] getServletMappings() {
             return new String[]{"/"};
         }
            
         @Override
         public void onStartup(ServletContext servletContext) throws ServletException {
             super.onStartup(servletContext);
            
             // 添加Filter
             //post请求解决乱码问题
             FilterRegistration.Dynamic encodingFilter = servletContext.addFilter("CharacterEncodingFilter", new CharacterEncodingFilter("UTF-8"));
             encodingFilter.addMappingForUrlPatterns(null, false, "/*");
         }
     }
    
  2. 该类的本质是:项目部署的时候创建该对象,然后调用onStartup方法,该方法内部会自动调用getRootConfigClasses、getServletConfigClasses、getServletMappings对应的方法

Initializer的本质

  1. AbstractAnnotationConfigDispatcherServletInitializer的本质
    1. 最终是实现了WebApplicationInitializer接口
    2. 项目部署到Web容器时,就会初始化实现了WebApplicationInitializer接口的实例,并调用它的onStartup方法
  2. 也可以自己定义一个类WebInitializer2,实现WebApplicationInitializer接口,然后主动调用父子容器等方法

     public class WebInitializer2 implements WebApplicationInitializer {
         @Override
         public void onStartup(ServletContext servletContext) throws ServletException {
             // 父容器配置
             AnnotationConfigWebApplicationContext springCtx = new AnnotationConfigWebApplicationContext();
             springCtx.register(SpringConfig.class);
             // 通过监听器加载配置信息
             servletContext.addListener(new ContextLoaderListener(springCtx));
        
             // 子容器配置
             AnnotationConfigWebApplicationContext mvcCtx = new AnnotationConfigWebApplicationContext();
             mvcCtx.register(SpringMVCConfig.class);
                
             //交给DispatcherServlet进行初始化子容器
             ServletRegistration.Dynamic servlet = servletContext.addServlet(
                     "DispatcherServlet",
                     new DispatcherServlet(mvcCtx));
             servlet.setLoadOnStartup(0);
             servlet.addMapping("/");
        
             // filter
             FilterRegistration.Dynamic encodingFilter = servletContext.addFilter(
                     "CharacterEncodingFilter",
                     new CharacterEncodingFilter("UTF-8"));
             encodingFilter.addMappingForUrlPatterns(null, false, "/*");
         }
     }
    

创建父子容器

  1. 纯注解实现Spring容器,取代applicationContext.xml
    1. 注意:SpringConfig可以不需要再写@Configuration
     //父容器存放service、dao
     //converter其他也会用到,所以放到父容器中
     @ComponentScan({"com.zh.service", "com.zh.converter"})
     @PropertySource("classpath:db.properties")
     @MapperScan("${mybatis.mapperScan}")
     @EnableTransactionManagement
     public class SpringConfig {
         @Value("${jdbc.driverClassName}")
         private String driverClassName;
         @Value("${jdbc.url}")
         private String url;
         @Value("${jdbc.username}")
         private String username;
         @Value("${jdbc.password}")
         private String password;
         @Value("${mybatis.typeAliasesPackage}")
         private String typeAliasesPackage;
         //自动注入
         @Value("${mybatis.configLocation}")
         private String configLocation;
        
         @Bean
         public DataSource dataSource() {
             DruidDataSource ds = new DruidDataSource();
             ds.setDriverClassName(driverClassName);
             ds.setUrl(url);
             ds.setUsername(username);
             ds.setPassword(password);
             return ds;
         }
        
         @Bean
         public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
             SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
             bean.setDataSource(dataSource);
             bean.setTypeAliasesPackage(typeAliasesPackage);
             //单独加载mybaits核心配置文件
             bean.setConfigLocation(new ClassPathResource(configLocation));
             return bean;
         }
        
         @Bean
         public DataSourceTransactionManager txMgr(DataSource dataSource) {
             DataSourceTransactionManager mgr = new DataSourceTransactionManager();
             mgr.setDataSource(dataSource);
             return mgr;
         }
     }
    
  2. 纯注解实现SpringMVC容器,取代dispatcherServlet.xml

     //子容器存放controller、拦截器(仅仅用于controller层)
     @ComponentScan({"com.zh.controller", "com.zh.interceptor"})
     @EnableWebMvc
     public class SpringMVCConfig implements WebMvcConfigurer {
        
         //自动注入拦截器
         @Autowired
         private MyInterceptor myInterceptor;
         @Autowired
         private DateConverter dateConverter;
         //将拦截器对象放入容器
         @Bean
         public MyInterceptor myInterceptor() {
             return new MyInterceptor();
         }
        
         //前后缀拼接
         @Bean
         public InternalResourceViewResolver viewResolver() {
             InternalResourceViewResolver resolver = new InternalResourceViewResolver();
             resolver.setPrefix("/WEB-INF/page/");
             resolver.setSuffix(".jsp");
             return resolver;
         }
         //文件上传,相当于<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
         @Bean
         public CommonsMultipartResolver multipartResolver() {
             CommonsMultipartResolver resolver = new CommonsMultipartResolver();
             resolver.setDefaultEncoding("UTF-8");
             return resolver;
         }
        
         //设置拦截器,拦截路径,相当于 <mvc:interceptors>
         @Override
         public void addInterceptors(InterceptorRegistry registry) {
             registry.addInterceptor(myInterceptor)
                     .addPathPatterns("/**")
                     .excludePathPatterns("/asset/**");
         }
        
         //相当于<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
         @Override
         public void addFormatters(FormatterRegistry registry) {
             registry.addConverter(dateConverter);
         }
        
         /**
          * 相当于<mvc:default-servlet-handler/>
          * 用以处理静态资源
          */
         @Override
         public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
             configurer.enable();
         }
        
         //设置返回String、json响应数据的编码 MessageConverters,相当于<mvc:message-converters>
         @Override
         public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
             // 设置返回的普通字符串的编码
             StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();
             stringConverter.setDefaultCharset(StandardCharsets.UTF_8);
             converters.add(stringConverter);
        
             // 设置返回的JSON数据的编码
             MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
             jsonConverter.setDefaultCharset(StandardCharsets.UTF_8);
             converters.add(jsonConverter);
         }
     }
    

其他代码说明

  1. service、dao、domain、controller都没有变化
  2. 新增MyInterceptor

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

     @Component
     public class DateConverter implements Converter<String, Date> {
         @Override
         public Date convert(String source) {
             try {
                 return new SimpleDateFormat("yyyy-MM-dd").parse(source);
             } catch (ParseException e) {
                 e.printStackTrace();
                 return null;
             }
         }
     }
    
  4. controller添加测试

     @Controller
     public class TestControlller {
         @GetMapping("/test1")
         public String test1() {
             // /WEB-INF/page/test.jsp
             return "test";
         }
        
         @GetMapping("/test2")
         @ResponseBody
         public String test2() {
             return "测试中文数据";
         }
        
         @GetMapping("/test3")
         @ResponseBody
         public String test3(@RequestParam("birthday") Date birthday) {
             return birthday.toString();
         }
        
         @PostMapping("/test4")
         @ResponseBody
         public String test4(@RequestParam("name") String name,
                             @RequestParam("photo") MultipartFile photo) {
             return "Success - " + name + " - " + photo.toString();
         }
     }
    
  5. db.properties

     jdbc.driverClassName=com.mysql.jdbc.Driver
     jdbc.url=jdbc:mysql://localhost:3306/test-mybatis
     jdbc.username=root
     jdbc.password=root
        
     mybatis.typeAliasesPackage=com.zh.domain
     mybatis.mapperScan=com.zh.dao
     mybatis.configLocation=mybatis-config.xml
    
Table of Contents