框架升级之springMvc+spring+mybatis 转 springBoot

项目说明:

1.前后端分离的web项目-后台管理系统

2.外置tomcat,保留web.xml

3.打包方式:war

4.yml配置

应用场景:

1.支持多数据源

2.文件上传

3.定时

4.异步

5.shiro 权限整合

6.log4j

二.案例

项目结构:

1.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>demo</groupId>
    <artifactId>demo</artifactId>
    <version>1.0.0</version>
    <packaging>war</packaging>
    <name>demo</name>
    <description>demo</description>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <jackson.version>2.9.5</jackson.version>
        <log4j2.version>2.6.2</log4j2.version>
    </properties>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <finalName>demo##${project.version}</finalName>
    </build>
    <dependencies>
        <!-- JDBC -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- web项目 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 剔除掉springBoot内嵌的tomcat-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- 日志 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- 数据库连接 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-dbcp2</artifactId>
            <version>2.1.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.18</version>
        </dependency>
        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- 针对tomcat的版本问题而导入包 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.4.3.Final</version>
        </dependency>
        <!-- 文件上传 -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- spring session + redis -->
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>
        <!-- jedis -->
        <!-- <dependency>
             <groupId>redis.clients</groupId>
             <artifactId>jedis</artifactId>
             <version>2.9.0</version>
         </dependency>-->
        <!-- alibaba的druid数据库连接池 -->
        <!-- <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid-spring-boot-starter</artifactId>
             <version>1.1.9</version>
         </dependency>-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.16</version>
        </dependency>
        <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <!-- <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <version>3.0.1</version>
             <scope>provided</scope>
         </dependency>-->
    </dependencies>
</project>
 

2.application.yml

#切换不同运行环境的配置
spring:
  profiles:
    active: local


---
#开发配置
spring:
  profiles: local

  # double mysql datasource
  datasource:
    # 数据源1
    db1:
      jdbc-url: 
      username: 
      password: 
      driver-class-name: com.mysql.cj.jdbc.Driver
      #      type: com.alibaba.druid.pool.DruidDataSource
      type: org.apache.commons.dbcp2.BasicDataSource
      dbcp2:
        initialSize: 2
        maxTotal: 4
        minIdle: 2
        maxWaitMillis: 5000
        validationQuery: select 1
        maxConnLifetimeMillis: 43200000
        timeBetweenEvictionRunsMillis: 14400000
        numTestsPerEvictionRun: 500
  # 数据源2
  #db2:

  # session
  session:
    store-type: none
  #停用jmx监控,tomcat多个项目使用相同数据源名时会部署失败;
  jmx:
    enabled: false
# mybatis backpage
mybatis:
  typeAliasesPackage: demo.model
  #mapperLocations: classpath:mapper/*.xml


---
#test environment
spring:
  profiles: test

  datasource:
    # db1
    db1:
      jdbc-url: 
      username: 
      password: 
      driver-class-name: com.mysql.cj.jdbc.Driver
      #      type: com.alibaba.druid.pool.DruidDataSource
      type: org.apache.commons.dbcp2.BasicDataSource
      dbcp2:
        initialSize: 2
        maxTotal: 4
        minIdle: 2
        maxWaitMillis: 5000
        validationQuery: select 1
        maxConnLifetimeMillis: 43200000
        timeBetweenEvictionRunsMillis: 14400000
        numTestsPerEvictionRun: 500
  # db2
  #db2:

  # session
  session:
    store-type: none
  jmx:
    enabled: false
# mybatis backpage
mybatis:
  typeAliasesPackage: demo.model
  #config-location:

 

3.web.xml

依旧在webapp->WEB-INF下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID"
         version="3.0">
    <display-name>demo</display-name>
    <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>
    </filter>
    <filter-mapping>
        <filter-name>characterEncodingFilter</filter-name>
        <url-pattern>/</url-pattern>
    </filter-mapping>
    <session-config>//session的有效时间
        <session-timeout>300</session-timeout>
        <cookie-config>
            <name>BACKEND</name>
            <path>/</path>
        </cookie-config>
    </session-config>
</web-app>

4.应用主程序: SpringBootApplication

**
 * 启动类
 */
// controller,service等扫描路径 : 默认扫描和启动类同个包下文件
@EnableScheduling // 启用spring定时
@EnableTransactionManagement//数据库事务
@EnableAsync //异步
@SpringBootApplication
public class SpringBootBackApplication extends SpringBootServletInitializer {

   public static void main(String[] args) {
      SpringApplication.run(SpringBootBackApplication.class, args);
   }

   @Override
   protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      return application.sources(SpringBootBackApplication.class);
   }

   /**
    * 去除multipartResolver 冲突,上传文件配置
    * 
    * @return
    */
   @Bean(name = "multipartResolver")
   public CommonsMultipartResolver multipartResolver() {
      CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
      multipartResolver.setDefaultEncoding("UTF-8");
      // resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
      // multipartResolver.setResolveLazily(true);
      multipartResolver.setMaxInMemorySize(5120);
      // 上传文件大小 30M 30*1024*1024
      multipartResolver.setMaxUploadSize(30 * 1024 * 1024);
      return multipartResolver;
   }
   /**
    * 文件上传配置
    * 
    * @return
    */
   // @Bean
   // public MultipartConfigElement multipartConfigElement() {
   // MultipartConfigFactory factory = new MultipartConfigFactory();
   // // 单个文件最大
   // factory.setMaxFileSize("30MB"); // KB,MB
   // /// 设置总上传数据总大小
   // factory.setMaxRequestSize("30MB");
   // return factory.createMultipartConfig();
   // }
   /**
    * redis
    * 
    * @return
    */
   // @Bean
   // public static ConfigureRedisAction configureRedisAction() {
   // return ConfigureRedisAction.NO_OP;
   // }
}

5.config 配置类

5.1数据源注册

/*
 * db1的数据源,事务,工厂等配置
 */
@Configuration
@MapperScan(basePackages = "hotkidclub.mapper", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class MasterDataSourceConfig {

   @Bean
   @ConfigurationProperties(prefix = "spring.datasource.db1")
   @Primary
   public DataSource db1DataSource() {
      return DataSourceBuilder.create().build();
   }

   @Bean
   @Primary
   public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
      SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
      bean.setDataSource(dataSource);
      bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:hotkidclub/mapper/*.xml"));
      return bean.getObject();
   }

   @Bean
   @Primary
   public DataSourceTransactionManager db1TransactionManager(@Qualifier("db1DataSource") DataSource dataSource) {
      return new DataSourceTransactionManager(dataSource);
   }

   @Bean
   @Primary
   public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
      return new SqlSessionTemplate(sqlSessionFactory);
   }
}

5.2 Mvc 可根据具体应用场景配置

/**
 * Mvc相关配置
 *
 * Interceptors:拦截器
 *
 * ArgumentResolvers: 参数绑定解析器
 *
 * ViewControllers:页面跳转
 *
 * ResourceHandlers:静态资源
 *
 * configureDefaultServletHandling:默认静态资源处理器
 *
 * configureViewResolvers:视图解析器
 *
 * configureContentNegotiation:配置内容裁决的一些参数
 *
 * addCorsMappings:跨域
 *
 * configureMessageConverters:信息转换器
 */
@Configuration
public class WebConfigurer implements WebMvcConfigurer {

   @Autowired
   private LoggedInInterceptor loggedInInterceptor;
   @Autowired
   private LoginUserInfoResolver loginUserInfoResolver;

   /**
    * 配置静态资源:html,js,css,等等
    * 
    * @param registry
    */
   @Override
   public void addResourceHandlers(ResourceHandlerRegistry registry) {
   }

   /**
    * 注册拦截器:自定义的拦截器需要通过这里添加注册才能生效
    *
    *
    * @param registry
    */
   // @Override
   // public void addInterceptors(InterceptorRegistry registry) {
   // registry.addInterceptor(loggedInInterceptor).addPathPatterns("/**").excludePathPatterns("/login.ctrl");// 添加请求路径拦截,以及不包含的路径(不拦截)
   // registry.addInterceptor(loggedInInterceptor);// 在注册时不指定拦截路径,通过拦截器中判断是否函数带有isLogin(自定义)的注解来拦截
   // }
   /**
    * 注册:参数绑定解析器
    * 
    * @param argumentResolvers
    */
   @Override
   public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
      //argumentResolvers.add(loginUserInfoResolver);
   }
}

6.shiro 相关

6.1 自定义realm

/**
 * shiro 核心组件-realm : 处理用户资源权限,实现认证和授权
 */
public class ShiroRealm extends AuthorizingRealm {

   @Autowired
   RoleService roleService;

   /**
    * 认证器 :
    * <p>
    * 本平台用户登入接口调用-subject.login() : 回调该函数
    * </p>
    * 
    * @param authcToken 凭证信息:可存放用户账号密码
    * @return 认证信息:包含当前请求登入的用户信息
    * @throws AuthenticationException
    */
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
      Subject subject = SecurityUtils.getSubject();
      // 1.获取认证的主体信息:账户密码
      UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
      // 2.可校验数据库存储的账号密码(本系统在登入接口的service层已处理)
      // 3.创建简单认证信息对象可存放相关信息 : (object, object, 字符串);可传递自定义对象,字符内容;
      // Session session = subject.getSession();
      // session.setAttribute("user", token.getPrincipal());
      SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), getName());
      return info;
   }

   /**
    * 授权器 : 校验用户的角色和权限
    * <p>
    * 本平台接口配置角色/权限的授权注解时 : 回调该函数
    * </p>
    * 
    * @param principalCollection
    * @return
    */
   @Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
      String principal = (String) principalCollection.getPrimaryPrincipal();
      SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
      // 1.通过用户名去数据库查询该用户的角色和权限
      Map<String, Object> verifyInfo = roleService.getAuthorizationInfo(principal);
      Set<String> rs = (Set) verifyInfo.get("roleNames");
      Set<String> ps = (Set) verifyInfo.get("permissionCodes");
      // 2.设置角色信息
      if (rs != null && rs.size() > 0) {
         info.addRoles(rs);
      }
      // 3.设置权限信息
      if (ps != null && ps.size() > 0) {
         info.addStringPermissions(ps);
      }
      return info;
   }
}

6.2自定义异常

public class AuthenticationFilter extends FormAuthenticationFilter {
   //未登入
   @Override
   protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
      response.setContentType("application/json; charset=utf-8");
      response.setCharacterEncoding("UTF-8");
      response.getWriter().print("{\"errorCode\":444,\"errorMsg\":\"未登入\"}");
      response.flushBuffer();
      return false;
   }
}
/**
 * 全局未授权异常-捕获&处理
 *
 * 本项目使用场景: shiro鉴权时抛出的未授权异常未处理直接响应客户端,使用全局异常注解@ControllerAdvice 捕获处理
 *
 */
@RestControllerAdvice
public class UnauthorizedExceptionHandler {

   /**
    * 处理UnauthorizedException
    * 
    * @param req
    * @param e
    * @return
    */
   @ExceptionHandler(value = UnauthorizedException.class)
   public Map<?, ?> defaultExceptionHandler(HttpServletRequest req, Exception e) {
      Map<String, Object> exception_response = new HashMap<>();
      exception_response.put("errorCode", 445);
      exception_response.put("errorMsg", "拒绝访问-权限不足");
      return exception_response;
   }
}

 

后期持续更新springBoot的各种应用场景...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章