框架升級之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的各種應用場景...

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