Przeglądaj źródła

0723 01 基础工程

hr 4 lat temu
rodzic
commit
a197e72ed2
25 zmienionych plików z 1698 dodań i 17 usunięć
  1. 136 2
      pom.xml
  2. 3 1
      src/main/java/com/imed/costaccount/CostAccountApplication.java
  3. 56 0
      src/main/java/com/imed/costaccount/common/config/CorsConfig.java
  4. 164 0
      src/main/java/com/imed/costaccount/common/shiro/OAuth2Filter.java
  5. 90 0
      src/main/java/com/imed/costaccount/common/shiro/OAuth2Realm.java
  6. 37 0
      src/main/java/com/imed/costaccount/common/shiro/OAuth2Token.java
  7. 77 0
      src/main/java/com/imed/costaccount/common/shiro/ShiroConfig.java
  8. 55 0
      src/main/java/com/imed/costaccount/common/swagger/SwaggerConfig.java
  9. 45 0
      src/main/java/com/imed/costaccount/common/token/JwtUtil.java
  10. 52 0
      src/main/java/com/imed/costaccount/common/token/RedisConfig.java
  11. 270 0
      src/main/java/com/imed/costaccount/common/token/RedisUtil.java
  12. 21 0
      src/main/java/com/imed/costaccount/common/token/ThreadLocalToken.java
  13. 106 0
      src/main/java/com/imed/costaccount/common/util/AesUtil.java
  14. 150 0
      src/main/java/com/imed/costaccount/common/util/BeanUtil.java
  15. 102 0
      src/main/java/com/imed/costaccount/common/util/PageUtils.java
  16. 123 0
      src/main/java/com/imed/costaccount/common/util/Result.java
  17. 26 0
      src/main/java/com/imed/costaccount/common/xss/XssFilter.java
  18. 124 0
      src/main/java/com/imed/costaccount/common/xss/XssHttpServletRequestWrapper.java
  19. 7 0
      src/main/java/com/imed/costaccount/mapper/DemoMapper.java
  20. 15 0
      src/main/java/com/imed/costaccount/model/Demo.java
  21. 7 0
      src/main/java/com/imed/costaccount/service/DemoService.java
  22. 13 0
      src/main/java/com/imed/costaccount/service/impl/DemoServiceImpl.java
  23. 16 0
      src/main/java/com/imed/costaccount/web/DemoController.java
  24. 3 1
      src/main/resources/application.yml
  25. 0 13
      src/test/java/com/imed/costaccount/CostAccountApplicationTests.java

+ 136 - 2
pom.xml

@@ -5,21 +5,53 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>2.4.10-SNAPSHOT</version>
+        <version>2.2.4.RELEASE</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
     <groupId>com.imed</groupId>
     <artifactId>CostAccount</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <name>CostAccount</name>
-    <description>Demo project for Spring Boot</description>
+    <description>成本核算</description>
     <properties>
         <java.version>1.8</java.version>
     </properties>
+
     <dependencies>
+        <!--日志-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <version>2.2.4.RELEASE</version>
+        </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>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.9</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
 
         <dependency>
@@ -27,6 +59,108 @@
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
+
+        <!--junit-->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!--aop-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <!--        <dependency>-->
+        <!--            <groupId>org.springframework.boot</groupId>-->
+        <!--            <artifactId>spring-boot-devtools</artifactId>-->
+        <!--            <scope>runtime</scope>-->
+        <!--            <optional>true</optional>-->
+        <!--        </dependency>-->
+
+
+        <!--mysql mybatis-plus等依赖-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.3.1</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.baomidou</groupId>
+                    <artifactId>mybatis-plus-generator</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <!--最好指定版本,不同环境版本可能不同-->
+            <version>5.1.17</version>
+        </dependency>
+
+
+        <!--数据连接池-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>1.1.13</version>
+        </dependency>
+
+        <!--hutool 个人习惯使用-->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.5.7</version>
+        </dependency>
+
+        <!--lombok-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>swagger-bootstrap-ui</artifactId>
+            <version>1.9.1</version>
+        </dependency>
+
+        <!--shiro-->
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-web</artifactId>
+            <version>1.5.3</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-spring</artifactId>
+            <version>1.5.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>3.10.3</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 3 - 1
src/main/java/com/imed/costaccount/CostAccountApplication.java

@@ -1,13 +1,15 @@
 package com.imed.costaccount;
 
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 
+@MapperScan(basePackages = {"com.imed.costaccount.mapper"})
 @SpringBootApplication
 public class CostAccountApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(CostAccountApplication.class, args);
     }
-
 }

+ 56 - 0
src/main/java/com/imed/costaccount/common/config/CorsConfig.java

@@ -0,0 +1,56 @@
+//package com.imed.costaccount.common.config;
+//
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.web.cors.CorsConfiguration;
+//import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+//import org.springframework.web.filter.CorsFilter;
+//import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+//import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+//
+///**
+// * @author huangrui
+// */
+//@Configuration
+//public class CorsConfig implements WebMvcConfigurer {
+//
+//
+//
+//    @Value("${file.filelocal}")
+//    private String fileLocal;
+//
+//    @Bean
+//    public CorsFilter corsFilter() {
+//        // 初始化cors配置对象
+//        CorsConfiguration configuration = new CorsConfiguration();
+//        // 允许跨域的域名,如果要携带cookie,不能写*。*:代表所有域名都可以跨域访问
+//        configuration.addAllowedOrigin("*");
+//        configuration.setAllowCredentials(true); // 允许携带cookie
+//        configuration.addAllowedMethod("*"); // 代表所有的请求方法:GET POST PUT Delete。。。。
+//        configuration.addAllowedHeader("*"); // 允许携带任何头信息
+//
+//        // 初始化cors配置源对象
+//        UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource();
+//        configurationSource.registerCorsConfiguration("/**", configuration);
+//
+//        // 返回corsFilter实例,参数:cors配置源对象
+//        return new CorsFilter(configurationSource);
+//    }
+//
+//    /**
+//     * 实现静态资源访问,但是这里仅仅提供了classpath下static文件夹的转发
+//     * 对于解决其他目录的需要重新修改
+//     * @param registry
+//     */
+//    @Override
+//    public void addResourceHandlers(ResourceHandlerRegistry registry) {
+//        registry.addResourceHandler("/**")
+//                .addResourceLocations("classpath:/static/**")
+//                .addResourceLocations(fileLocal);//映射本地静态资源
+//    }
+//
+//
+//
+//
+//}

+ 164 - 0
src/main/java/com/imed/costaccount/common/shiro/OAuth2Filter.java

@@ -0,0 +1,164 @@
+//package com.imed.costaccount.common.shiro;
+//
+//import cn.hutool.core.util.StrUtil;
+//import cn.hutool.json.JSONUtil;
+//import com.imed.costaccount.common.util.Result;
+//import com.imed.costaccount.common.config.RedisUtil;
+//import com.imed.costaccount.common.token.JwtUtil;
+//import com.imed.costaccount.common.token.ThreadLocalToken;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.shiro.authc.AuthenticationException;
+//import org.apache.shiro.authc.AuthenticationToken;
+//import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.context.annotation.Scope;
+//import org.springframework.stereotype.Component;
+//import org.springframework.web.bind.annotation.RequestMethod;
+//
+//import javax.servlet.FilterChain;
+//import javax.servlet.ServletException;
+//import javax.servlet.ServletRequest;
+//import javax.servlet.ServletResponse;
+//import javax.servlet.http.HttpServletRequest;
+//import javax.servlet.http.HttpServletResponse;
+//import java.io.IOException;
+//
+//@Slf4j
+//@Scope("prototype")
+//@Component
+//public class OAuth2Filter extends AuthenticatingFilter {
+//
+//    @Autowired
+//    private JwtUtil jwtUtil;
+//
+//    @Autowired
+//    private ThreadLocalToken local;
+//
+//    @Autowired
+//    private RedisUtil redisUtil;
+//
+//
+//    @Value("${pfm.jwt.expire}")
+//    private int expire;
+//
+//    /**
+//     * 判断是否需要交由shiro处理,一般options 请求类型不需要
+//     * @return <code>true</code> if request should be allowed access
+//     * @param request
+//     * @param response
+//     * @param mappedValue
+//     */
+//    @Override
+//    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+//        HttpServletRequest req = (HttpServletRequest) request;
+//        if (req.getMethod().equals(RequestMethod.OPTIONS.name())) {
+//            return true;
+//        }
+//        return false;
+//    }
+//
+//    /**
+//     * 将token封装为auth2Token 返回交由shiro处理
+//     * @param servletRequest
+//     * @param servletResponse
+//     * @return
+//     * @throws Exception
+//     */
+//    @Override
+//    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
+//        HttpServletRequest request = (HttpServletRequest) servletRequest;
+//        String token = this.getRequestToken(request);
+//        if (StrUtil.isBlank(token)) {
+//            return null;
+//        }
+//        return new OAuth2Token(token);
+//    }
+//
+//    /**
+//     * 验证token,并进行相应处理(是否过期,续期等)
+//     * @param request
+//     * @param response
+//     * @return
+//     * @throws Exception
+//     */
+//    @Override
+//    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+//        HttpServletRequest req = (HttpServletRequest) request;
+//        HttpServletResponse resp = (HttpServletResponse) response;
+//        resp.setContentType("text/html");
+//        resp.setCharacterEncoding("UTF-8");
+//        // 允许跨域
+//        resp.setHeader("Access-Control-Allow-Credentials", "true");
+//        resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
+//
+//        local.clear();
+//        String token = this.getRequestToken(req);
+//        if (StrUtil.isBlank(token)) {
+//            String json = JSONUtil.toJsonStr(Result.errorMsg(499, "无效的令牌,请登录"));
+//            resp.getWriter().print(json);
+//            return false;
+//        }
+//        // 判断redis中是否存在该用户的token,如果不存在或者不一致那么标识token无效
+//        int userId = jwtUtil.getUserId(token);
+//        String str = (String) redisUtil.get(userId + "");
+//        if (StrUtil.isBlank(str)) {
+//            String json = JSONUtil.toJsonStr(Result.errorMsg(499, "无效的令牌,请登录"));
+//            resp.getWriter().print(json);
+//            return false;
+//        }
+//        if (!str.equalsIgnoreCase(token)) {
+//            String json = JSONUtil.toJsonStr(Result.errorMsg(499, "无效的令牌,请登录"));
+//            resp.getWriter().print(json);
+//            return false;
+//        }
+//
+//        // 内容是否过期
+//        try {
+//            jwtUtil.verifierToken(token);
+//        } catch (Exception e) {
+////            // 无效的令牌
+//            resp.setStatus(400);
+//            resp.getWriter().print("无效的令牌");
+//            String json = JSONUtil.toJsonStr(Result.errorMsg(499, "无效的令牌"));
+//            resp.getWriter().print(json);
+//            return false;
+//        }
+//        // 执行realm
+//        local.setToken(token);
+//        return executeLogin(request, response);
+//    }
+//
+//    @Override
+//    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
+//        HttpServletRequest req = (HttpServletRequest) request;
+//        HttpServletResponse resp = (HttpServletResponse) response;
+//        resp.setContentType("text/html");
+//        resp.setCharacterEncoding("UTF-8");
+//        // 允许跨域
+//        resp.setHeader("Access-Control-Allow-Credentials", "true");
+//        resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
+//        resp.setStatus(400);
+//        try {
+//            resp.getWriter().print(e.getMessage());
+//        } catch (IOException ioException) {
+//            ioException.printStackTrace();
+//        }
+//        return false;
+//    }
+//
+//
+//    private String getRequestToken(HttpServletRequest request) {
+//        String token = request.getHeader("token");
+//
+//        if (StrUtil.isBlank(token)) {
+//            token = request.getParameter("token");
+//        }
+//        return token;
+//    }
+//
+//    @Override
+//    public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
+//        super.doFilterInternal(request, response, chain);
+//    }
+//}

+ 90 - 0
src/main/java/com/imed/costaccount/common/shiro/OAuth2Realm.java

@@ -0,0 +1,90 @@
+//package com.imed.costaccount.common.shiro;
+//
+//import cn.hutool.core.util.StrUtil;
+//import com.imed.costaccount.common.token.JwtUtil;
+//import lombok.extern.slf4j.Slf4j;
+//import org.apache.shiro.authc.AuthenticationException;
+//import org.apache.shiro.authc.AuthenticationInfo;
+//import org.apache.shiro.authc.AuthenticationToken;
+//import org.apache.shiro.authc.SimpleAuthenticationInfo;
+//import org.apache.shiro.authz.AuthorizationInfo;
+//import org.apache.shiro.authz.SimpleAuthorizationInfo;
+//import org.apache.shiro.realm.AuthorizingRealm;
+//import org.apache.shiro.subject.PrincipalCollection;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.stereotype.Component;
+//
+//import java.util.Arrays;
+//import java.util.Objects;
+//import java.util.Set;
+//import java.util.stream.Collectors;
+//
+///**
+// * 认证和授权在这里操作
+// */
+//@Slf4j
+//@Component
+//public class OAuth2Realm extends AuthorizingRealm {
+//
+//    @Autowired
+//    private JwtUtil jwtUtil;
+//
+//
+//    /**
+//     * 是否需要认证
+//     * @param token
+//     * @return
+//     */
+//    @Override
+//    public boolean supports(AuthenticationToken token) {
+//        return token instanceof com.imed.costaccount.common.shiro.OAuth2Token;
+//    }
+//
+//    /**
+//     * 登录认证
+//     * @param token token
+//     * @return
+//     * @throws AuthenticationException
+//     */
+//    @Override
+//    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+//        String principal = (String) token.getPrincipal();
+//        if (StrUtil.isEmpty(principal)) {
+//            log.error("当前请求未携带token");
+////            throw new PfmException(PfmExceptionEnum.ForbiddenException);
+//            // TODO: 2021/7/23
+//        }
+//        int userId = jwtUtil.getUserId(principal);
+////        SysEmployee employee = employeeService.queryById(userId);
+////        if (Objects.isNull(employee)) {
+////            log.error("当前token{}", principal);
+////            throw new PfmException(499, "登录失败,请重新登录");
+////        }
+//
+//        // TODO: 2021/7/23
+//        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(null, principal, getName());
+//        return info;
+//    }
+//
+//    /**
+//     * 授权对象
+//     * @param principals
+//     * @return
+//     */
+//    @Override
+//    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
+////        SysEmployee employee = (SysEmployee) principals.getPrimaryPrincipal();
+//
+//        // todo 根据后续需求完成动态配置
+////        String managerRole = employee.getManagerRole();
+////        String[] split = managerRole.split(StrUtil.COMMA);
+////        Set<String> permissions = Arrays.stream(split).map(RoleEnum::getRole).collect(Collectors.toSet());
+////        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
+////        info.setStringPermissions(permissions);
+////        return info;
+//        // TODO: 2021/7/23
+//        return null;
+//    }
+//
+//
+//}

+ 37 - 0
src/main/java/com/imed/costaccount/common/shiro/OAuth2Token.java

@@ -0,0 +1,37 @@
+//package com.imed.costaccount.common.shiro;
+//
+//import org.apache.shiro.authc.AuthenticationToken;
+//
+//public class OAuth2Token implements AuthenticationToken {
+//    private String token;
+//
+//    public OAuth2Token(String token) {
+//        this.token = token;
+//    }
+//
+//    public String getToken() {
+//        return token;
+//    }
+//
+//    public void setToken(String token) {
+//        this.token = token;
+//    }
+//
+//    /**
+//     * 返回授权主体
+//     * @return
+//     */
+//    @Override
+//    public Object getPrincipal() {
+//        return token;
+//    }
+//
+//    /**
+//     * 返回授权凭证
+//     * @return
+//     */
+//    @Override
+//    public Object getCredentials() {
+//        return token;
+//    }
+//}

+ 77 - 0
src/main/java/com/imed/costaccount/common/shiro/ShiroConfig.java

@@ -0,0 +1,77 @@
+//package com.imed.costaccount.common.shiro;
+//
+//import org.apache.shiro.mgt.SecurityManager;
+//import org.apache.shiro.spring.LifecycleBeanPostProcessor;
+//import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
+//import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+//import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//
+//import javax.servlet.Filter;
+//import java.util.HashMap;
+//import java.util.LinkedHashMap;
+//import java.util.Map;
+//
+//@Configuration
+//public class ShiroConfig {
+//
+//    @Bean("securityManager")
+//    public SecurityManager securityManager(OAuth2Realm realm) {
+//        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
+//        defaultWebSecurityManager.setRealm(realm);
+//        defaultWebSecurityManager.setRememberMeManager(null);
+//        return defaultWebSecurityManager;
+//    }
+//
+//    @Bean("shiroFilter")
+//    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,OAuth2Filter filter) {
+//        ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
+//        filterFactoryBean.setSecurityManager(securityManager);
+//        // OAuth2过滤
+//        Map<String, Filter> filters = new HashMap<>();
+//        filters.put("oauth2", filter);
+//        filterFactoryBean.setFilters(filters);
+//
+//        // HTTP请求过滤
+//        Map<String, String> filterMap = new LinkedHashMap<>();
+//        filterMap.put("/webjars/**", "anon");
+//        filterMap.put("/druid/**", "anon");
+//        filterMap.put("/app/**", "anon");
+//        filterMap.put("/sys/login", "anon");
+//        filterMap.put("/swagger/**", "anon");
+//        filterMap.put("/v2/api-docs", "anon");
+//        filterMap.put("/swagger-ui.html", "anon");
+//        filterMap.put("/static/js/**", "anon");
+//        filterMap.put("/doc.html", "anon");
+//        filterMap.put("/swagger-resources/**", "anon");
+//        filterMap.put("/captcha.jpg", "anon");
+//        filterMap.put("/user/register", "anon");
+//        filterMap.put("/employee/demo", "anon");
+//        filterMap.put("/employee/login", "anon");
+//        filterMap.put("/**/*.jpg", "anon");
+//        filterMap.put("/**/*.png", "anon");
+//
+//        // 除了以上的,其他的都使用oauth2过滤器
+//        filterMap.put("/**", "oauth2");
+//        filterFactoryBean.setFilterChainDefinitionMap(filterMap);
+//        return filterFactoryBean;
+//    }
+//
+//    @Bean("lifecycleBeanPostProcessor")
+//    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
+//        return new LifecycleBeanPostProcessor();
+//    }
+//
+//    /**
+//     * AOP 使用 的通知点增强点
+//     * @param securityManager
+//     * @return
+//     */
+//    @Bean
+//    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
+//        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
+//        advisor.setSecurityManager(securityManager);
+//        return advisor;
+//    }
+//}

+ 55 - 0
src/main/java/com/imed/costaccount/common/swagger/SwaggerConfig.java

@@ -0,0 +1,55 @@
+package com.imed.costaccount.common.swagger;
+
+import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+@Configuration
+@EnableSwagger2
+@EnableSwaggerBootstrapUI
+public class SwaggerConfig implements WebMvcConfigurer {
+
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .useDefaultResponseMessages(false)
+                .apiInfo(apiInfo())
+                .select()
+                //加了ApiOperation注解的类,才生成接口文档
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                //包下的类,才生成接口文档
+                //.apis(RequestHandlerSelectors.basePackage("com.kongyw.controller"))
+                .paths(PathSelectors.any())
+                .build()
+                .securitySchemes(security());
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("成本核算")
+                .description("成本核算接口文档")
+                .termsOfServiceUrl("https://www.baitu.com")
+                .version("TEST 1.00")
+                .build();
+    }
+
+    private List<ApiKey> security() {
+        return newArrayList(
+                new ApiKey("token", "token", "header")
+        );
+    }
+}

+ 45 - 0
src/main/java/com/imed/costaccount/common/token/JwtUtil.java

@@ -0,0 +1,45 @@
+//package com.imed.costaccount.common.token;
+//
+//import cn.hutool.core.date.DateField;
+//import cn.hutool.core.date.DateTime;
+//import cn.hutool.core.date.DateUtil;
+//import com.auth0.jwt.JWT;
+//import com.auth0.jwt.algorithms.Algorithm;
+//import com.auth0.jwt.interfaces.DecodedJWT;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.stereotype.Component;
+//
+//import java.time.Duration;
+//import java.util.Date;
+//
+//@Component
+//public class JwtUtil {
+//
+//    @Value("${pfm.jwt.secret}")
+//    private String secret;
+//
+//    @Value("${pfm.jwt.expire}")
+//    private Integer expire;
+//
+//    @Autowired
+//    private RedisUtil redisUtil;
+//
+//    public String createToken(int empId) {
+//        Date date = DateUtil.offset(new DateTime(), DateField.DAY_OF_YEAR, expire).toJdkDate();
+//        Algorithm algorithm = Algorithm.HMAC256(secret);
+//        String token = JWT.create().withClaim("userId", empId).withExpiresAt(date).sign(algorithm);
+//        redisUtil.set(empId + "", token, Duration.ofDays(expire));
+//        return token;
+//    }
+//
+//    public int getUserId(String token) {
+//        DecodedJWT decode = JWT.decode(token);
+//        return decode.getClaim("userId").asInt();
+//    }
+//
+//    public void verifierToken(String token) {
+//        Algorithm algorithm = Algorithm.HMAC256(secret);
+//        JWT.require(algorithm).build().verify(token);
+//    }
+//}

+ 52 - 0
src/main/java/com/imed/costaccount/common/token/RedisConfig.java

@@ -0,0 +1,52 @@
+package com.imed.costaccount.common.token;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * @author :lilei
+ * @date :Created in 2020/8/20 16:20
+ * @description:
+ */
+@Configuration
+public class RedisConfig {
+
+//    @Bean
+//    public RedisCacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
+//        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
+//        cacheManager.se
+//    }
+
+    @Bean
+    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+        StringRedisTemplate redisTemplate = new StringRedisTemplate(redisConnectionFactory);
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+        // 使用Jackson2JsonRedisSerialize 替换默认序列化
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+        // 设置value的序列化规则和 key的序列化规则
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.afterPropertiesSet();
+        return redisTemplate;
+    }
+
+    @Bean
+    public HashOperations hashOperations(
+            @NotNull RedisTemplate redisTemplate) {
+        return redisTemplate.opsForHash();
+    }
+}

+ 270 - 0
src/main/java/com/imed/costaccount/common/token/RedisUtil.java

@@ -0,0 +1,270 @@
+package com.imed.costaccount.common.token;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.support.atomic.RedisAtomicLong;
+import org.springframework.stereotype.Component;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Redis的工具类文件, 注意结果可能不是你想要的,建议使用string
+ */
+@Component
+public class RedisUtil {
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    @Autowired
+    private HashOperations hashOperations;
+
+    /**
+     * 指定缓存失效时间
+     *
+     * @param key  键
+     * @param time 时间(秒)
+     * @return
+     */
+    public boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     *
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+    public long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public boolean hasKey(String key) {
+        try {
+            return redisTemplate.hasKey(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+    public Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param key 可以传一个值
+     */
+    @SuppressWarnings("unchecked")
+    public void del(Object key) {
+        redisTemplate.delete(key);
+    }
+
+    /**
+     * 普通缓存放入
+     *
+     * @param key   键
+     * @param value 值
+     * @return true成功 false失败
+     */
+    public boolean set(String key, Object value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key
+     * @param value
+     * @param duration 过期时间,灵活选择
+     * @return
+     */
+    public boolean set(String key, Object value, Duration duration) {
+        try {
+            redisTemplate.opsForValue().set(key, value, duration);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @return true成功 false 失败
+     */
+    public boolean set(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * Push到 队列List
+     *
+     * @param key
+     * @param value
+     * @param
+     */
+    public void leftPush(String key, Object value) {
+        redisTemplate.opsForList().leftPush(key, value);
+    }
+
+    /**
+     * Push到 队列List
+     *
+     * @param key
+     * @param value
+     * @param
+     */
+    public void leftPush(String key, Object value, long expireTime) {
+        redisTemplate.opsForList().leftPush(key, value);
+        expire(key, expireTime);
+    }
+
+    /**
+     * 从队列List中Pop出来对象
+     *
+     * @param key
+     * @return
+     */
+    public Object rightPop(String key) {
+        return redisTemplate.opsForList().rightPop(key);
+    }
+
+    /**
+     * 从队列List中Pop出来对象
+     *
+     * @param key
+     * @param t
+     * @param <T>
+     * @return
+     */
+    public <T> T rightPop(String key, Class<T> t) {
+        return (T) redisTemplate.opsForList().rightPop(key);
+    }
+
+    /**
+     * 对缓存在key中的值做减1操作
+     *
+     * @param key
+     */
+    public Long decrement(String key) {
+        return redisTemplate.opsForValue().increment(key, -1);
+    }
+
+    /**
+     * 不存在时设置, 返回true为设置成功
+     *
+     * @param key
+     * @param value
+     */
+    public boolean setIfAbsent(Object key, Object value) {
+        return redisTemplate.opsForValue().setIfAbsent(key, value);
+    }
+
+    /**
+     * 不存在时设置,同时设置过期时间 返回true为设置成功
+     *
+     * @param key
+     * @param value
+     * @param timeout
+     * @return
+     */
+    public boolean setIfAbsent(String key, Object value, Duration timeout) {
+        return redisTemplate.opsForValue().setIfAbsent(key, value, timeout);
+    }
+
+    public long incrementAndGet(String key) {
+        RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
+        return entityIdCounter.incrementAndGet();
+    }
+
+    /**
+     * 存hash值
+     *
+     * @param key
+     * @param hKey
+     * @param hValue
+     */
+    public void hPut(Object key, Object hKey, Object hValue) {
+        hashOperations.put(key, hKey, hValue);
+    }
+
+    /**
+     * 存hash值
+     *
+     * @param key
+     * @param map
+     */
+    public void hPutAll(Object key, Map map) {
+        hashOperations.putAll(key, map);
+    }
+
+    /**
+     * 查hash值
+     *
+     * @param key
+     * @return
+     */
+    public Map hEntries(Object key) {
+        return hashOperations.entries(key);
+    }
+
+    /**
+     * 查hash值
+     *
+     * @param key
+     * @param hKey
+     * @return
+     */
+    public Object hGet(Object key, Object hKey) {
+        return hashOperations.get(key, hKey);
+    }
+
+}

+ 21 - 0
src/main/java/com/imed/costaccount/common/token/ThreadLocalToken.java

@@ -0,0 +1,21 @@
+package com.imed.costaccount.common.token;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class ThreadLocalToken {
+
+    private ThreadLocal<String> threadLocal = new ThreadLocal<>();
+
+    public void setToken(String token) {
+        threadLocal.set(token);
+    }
+
+    public String getToken() {
+        return (String) threadLocal.get();
+    }
+
+    public void clear() {
+        threadLocal.remove();
+    }
+}

+ 106 - 0
src/main/java/com/imed/costaccount/common/util/AesUtil.java

@@ -0,0 +1,106 @@
+package com.imed.costaccount.common.util;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * @author :lilei
+ * @date :Created in 2020/1/9 14:35
+ * @description:AES
+ */
+public class AesUtil {
+    // 密钥
+    public static String key = "&qsh9li1KxZa9la@";
+
+    private static String charset = "utf-8";
+    // 偏移量
+    private static int offset = 16;
+    // 加密器类型:加密算法为AES,加密模式为CBC,补码方式为PKCS5Padding
+    private static String transformation = "AES/CBC/PKCS5Padding";
+    // 算法类型:用于指定生成AES的密钥
+    private static String algorithm = "AES";
+
+    /**
+     * 加密
+     *
+     * @param content
+     * @return
+     */
+    public static String encrypt(String content) {
+        return encrypt(content, key);
+    }
+
+    /**
+     * 解密
+     *
+     * @param content
+     * @return
+     */
+    public static String decrypt(String content) {
+        return decrypt(content, key);
+    }
+
+    /**
+     * 加密
+     *
+     * @param content 需要加密的内容
+     * @param key     加密密码
+     * @return
+     */
+    private static String encrypt(String content, String key) {
+        try {
+            //构造密钥
+            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
+            //创建初始向量iv用于指定密钥偏移量(可自行指定但必须为128位),因为AES是分组加密,下一组的iv就用上一组加密的密文来充当
+            IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
+            //创建AES加密器
+            Cipher cipher = Cipher.getInstance(transformation);
+            byte[] byteContent = content.getBytes(charset);
+            //使用加密器的加密模式
+            cipher.init(Cipher.ENCRYPT_MODE, skey, iv);
+            // 加密
+            byte[] result = cipher.doFinal(byteContent);
+            //使用BASE64对加密后的二进制数组进行编码
+            return new Base64().encodeToString(result);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * AES(256)解密
+     *
+     * @param content 待解密内容
+     * @param key     解密密钥
+     * @return 解密之后
+     * @throws Exception
+     */
+    private static String decrypt(String content, String key) {
+        try {
+            SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
+            IvParameterSpec iv = new IvParameterSpec(key.getBytes(), 0, offset);
+            Cipher cipher = Cipher.getInstance(transformation);
+            //解密时使用加密器的解密模式
+            cipher.init(Cipher.DECRYPT_MODE, skey, iv);// 初始化
+            byte[] result = cipher.doFinal(new Base64().decode(content));
+            return new String(result); // 解密
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static void main(String[] args) {
+        String s = "admin";
+        String encryptResultStr = encrypt(s);
+        // 加密
+        System.out.println("加密前:" + s);
+        System.out.println("加密后:" + encryptResultStr);
+        // 解密
+        System.out.println("解密后:" + decrypt(encryptResultStr));
+    }
+}

+ 150 - 0
src/main/java/com/imed/costaccount/common/util/BeanUtil.java

@@ -0,0 +1,150 @@
+package com.imed.costaccount.common.util;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.util.CollectionUtils;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+@Slf4j
+public final class BeanUtil {
+
+    /**
+     * 将对象转为为指定的对象
+     *
+     * @param source
+     * @param <T>
+     * @return
+     */
+    public static <T> T convertObj(Object source, Class<T> clazz) {
+        Object model = null;
+        if (source == null || clazz == null) {
+            return null;
+        }
+
+        try {
+            model = clazz.newInstance();
+        } catch (Exception e) {
+            log.error("将对象转为为指定的对象异常", e);
+        }
+        BeanUtils.copyProperties(source, model);
+        return (T) model;
+    }
+
+    public static <T> T convertObj(Object source, T result) {
+        BeanUtils.copyProperties(source, result);
+        return result;
+    }
+
+    public static <F, T> List<T> convertList(List<F> fromList, Class<T> tClass) {
+        List<T> tList = new ArrayList<>();
+        if (CollectionUtils.isEmpty(fromList)) {
+            return tList;
+        }
+        fromList.forEach(f -> tList.add(convertObj(f, tClass)));
+        return tList;
+    }
+
+    public static <F, T> List<T> convertListIgnoreCase(List<F> fromList, Class<T> clazz) {
+        List<T> tList = new ArrayList<>();
+        if (CollectionUtils.isEmpty(fromList)) {
+            return tList;
+        }
+        fromList.forEach(f -> {
+            try {
+                tList.add(copyIgnoreCase(f, clazz.newInstance()));
+            } catch (Exception e) {
+                log.error("将对象转为为指定的对象异常", e);
+            }
+        });
+        return tList;
+    }
+
+    /**
+     * 模仿Spring中 BeanUtils.copyProperties(source,target)
+     * 类型不同不可以转换
+     * 但是
+     * 大小写可以忽略
+     * 下划线 _ 被忽略
+     *
+     * @param source
+     * @param clazz
+     * @param <T>
+     * @return
+     */
+    public static <T> T copyIgnoreCase(Object source, Class<T> clazz) {
+        try {
+            return copyIgnoreCase(source, clazz.newInstance());
+        } catch (Exception e) {
+            log.error("将对象转为为指定的对象异常", e);
+        }
+        return null;
+    }
+
+    /**
+     * 模仿Spring中 BeanUtils.copyProperties(source,target)
+     * 类型不同不可以转换
+     * 但是
+     * 大小写可以忽略
+     * 下划线 _ 被忽略
+     *
+     * @param source
+     * @param target
+     * @param <T>
+     * @return
+     */
+    public static <T> T copyIgnoreCase(Object source, T target) {
+        Map<String, Field> sourceMap = CacheFieldMap.getFieldMap(source.getClass());
+        CacheFieldMap.getFieldMap(target.getClass()).forEach((k, it) -> {
+            Field field = sourceMap.get(k);
+            if (field != null && field.getType().equals(it.getType())) {
+                it.setAccessible(true);
+                field.setAccessible(true);
+                try {
+                    it.set(target, field.get(source));
+                } catch (Exception e) {
+                    log.error("对象复制错误", e);
+                }
+            }
+        });
+        return target;
+    }
+
+    private static class CacheFieldMap {
+        private static Map<String, Map<String, Field>> cacheMap = new HashMap<>();
+
+        private static final String SER_STR = "serialVersionUID";
+
+        private static Map<String, Field> getFieldMap(Class clazz) {
+            final String name = clazz.getName();
+            Map<String, Field> result = cacheMap.get(name);
+            if (result != null) {
+                return result;
+            }
+            synchronized (name) {
+                if (result != null) {
+                    return result;
+                }
+                Map<String, Field> fieldMap = new HashMap<>();
+                for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
+                    Arrays.stream(clazz.getDeclaredFields()).forEach(field -> {
+                                //忽略序列号字段
+                                if (SER_STR.equals(field.getName())) {
+                                    return;
+                                }
+                                fieldMap.put(field.getName().toLowerCase().replace("_", ""), field);
+                            }
+                    );
+                }
+                cacheMap.put(name, fieldMap);
+                return fieldMap;
+            }
+        }
+    }
+
+    public static <T> T copyProperties(Object source, T result) {
+        BeanUtils.copyProperties(source, result);
+        return result;
+    }
+}

+ 102 - 0
src/main/java/com/imed/costaccount/common/util/PageUtils.java

@@ -0,0 +1,102 @@
+package com.imed.costaccount.common.util;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 分页工具类
+ *
+ * @author Mark sunlightcs@gmail.com
+ */
+public class PageUtils implements Serializable {
+	private static final long serialVersionUID = 1L;
+	/**
+	 * 总记录数
+	 */
+	private int totalCount;
+	/**
+	 * 每页记录数
+	 */
+	private int pageSize;
+	/**
+	 * 总页数
+	 */
+	private int totalPage;
+	/**
+	 * 当前页数
+	 */
+	private int currPage;
+	/**
+	 * 列表数据
+	 */
+	private List<?> list;
+	
+	/**
+	 * 分页
+	 * @param list        列表数据
+	 * @param totalCount  总记录数
+	 * @param pageSize    每页记录数
+	 * @param currPage    当前页数
+	 */
+	public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
+		this.list = list;
+		this.totalCount = totalCount;
+		this.pageSize = pageSize;
+		this.currPage = currPage ;
+		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
+	}
+
+	/**
+	 * 分页
+	 */
+	public PageUtils(IPage<?> page) {
+		this.list = page.getRecords();
+		this.totalCount = (int)page.getTotal();
+		this.pageSize = (int)page.getSize();
+		this.currPage = (int)page.getCurrent();
+		this.totalPage = (int)page.getPages();
+	}
+
+	public int getTotalCount() {
+		return totalCount;
+	}
+
+	public void setTotalCount(int totalCount) {
+		this.totalCount = totalCount;
+	}
+
+	public int getPageSize() {
+		return pageSize;
+	}
+
+	public void setPageSize(int pageSize) {
+		this.pageSize = pageSize;
+	}
+
+	public int getTotalPage() {
+		return totalPage;
+	}
+
+	public void setTotalPage(int totalPage) {
+		this.totalPage = totalPage;
+	}
+
+	public int getCurrPage() {
+		return currPage;
+	}
+
+	public void setCurrPage(int currPage) {
+		this.currPage = currPage;
+	}
+
+	public List<?> getList() {
+		return list;
+	}
+
+	public void setList(List<?> list) {
+		this.list = list;
+	}
+	
+}

+ 123 - 0
src/main/java/com/imed/costaccount/common/util/Result.java

@@ -0,0 +1,123 @@
+package com.imed.costaccount.common.util;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * 统一封装返回对象
+ */
+public class Result {
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    // 响应业务状态
+    private Integer status;
+
+    // 响应消息
+    private String msg;
+
+    // 响应中的数据
+    private Object data;
+
+    @JsonIgnore
+    private String ok;	// 不使用
+
+    public static Result build(Integer status, String msg, Object data) {
+        return new Result(status, msg, data);
+    }
+
+    public static Result build(Integer status, String msg, Object data, String ok) {
+        return new Result(status, msg, data, ok);
+    }
+
+    public static Result ok(Object data) {
+        return new Result(data);
+    }
+
+    public static Result ok() {
+        return new Result(null);
+    }
+
+    public static Result errorMsg(String msg) {
+        return new Result(500, msg, null);
+    }
+    public static Result errorMsg(int code,String msg) {
+        return new Result(code, msg, null);
+    }
+
+    public static Result errorMap(Object data) {
+        return new Result(501, "error", data);
+    }
+
+    public static Result errorTokenMsg(String msg) {
+        return new Result(502, msg, null);
+    }
+
+    public static Result errorException(String msg) {
+        return new Result(555, msg, null);
+    }
+
+    public static Result errorUserQQ(String msg) {
+        return new Result(556, msg, null);
+    }
+
+    public Result() {
+
+    }
+
+    public Result(Integer status, String msg, Object data) {
+        this.status = status;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public Result(Integer status, String msg, Object data, String ok) {
+        this.status = status;
+        this.msg = msg;
+        this.data = data;
+        this.ok = ok;
+    }
+
+    public Result(Object data) {
+        this.status = 200;
+        this.msg = "success";
+        this.data = data;
+    }
+
+    public Boolean isOK() {
+        return this.status == 200;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+    public String getOk() {
+        return ok;
+    }
+
+    public void setOk(String ok) {
+        this.ok = ok;
+    }
+
+}

+ 26 - 0
src/main/java/com/imed/costaccount/common/xss/XssFilter.java

@@ -0,0 +1,26 @@
+package com.imed.costaccount.common.xss;
+
+import javax.servlet.*;
+import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+@WebFilter(urlPatterns = "/*")
+public class XssFilter implements Filter {
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        com.imed.costaccount.common.xss.XssHttpServletRequestWrapper wrapper = new com.imed.costaccount.common.xss.XssHttpServletRequestWrapper(request);
+        filterChain.doFilter(wrapper, servletResponse);
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}

+ 124 - 0
src/main/java/com/imed/costaccount/common/xss/XssHttpServletRequestWrapper.java

@@ -0,0 +1,124 @@
+package com.imed.costaccount.common.xss;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HtmlUtil;
+import cn.hutool.json.JSONUtil;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.*;
+import java.nio.charset.Charset;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
+    public XssHttpServletRequestWrapper(HttpServletRequest request) {
+        super(request);
+    }
+
+    @Override
+    public String getParameter(String name) {
+        String value = super.getParameter(name);
+        if (!StrUtil.hasEmpty(value)) {
+            value = HtmlUtil.filter(value);
+        }
+        return value;
+    }
+
+    @Override
+    public String[] getParameterValues(String name) {
+        String[] values = super.getParameterValues(name);
+        if (values != null) {
+            for (int i = 0; i < values.length; i++) {
+                String value = values[i];
+                if (!StrUtil.hasEmpty(value)) {
+                    value = HtmlUtil.filter(value);
+                }
+                values[i] = value;
+            }
+        }
+        return values;
+    }
+
+    @Override
+    public Map<String, String[]> getParameterMap() {
+        Map<String, String[]> parameters = super.getParameterMap();
+        LinkedHashMap<String, String[]> map = new LinkedHashMap();
+        if (parameters != null) {
+            for (String key : parameters.keySet()) {
+                String[] values = parameters.get(key);
+                for (int i = 0; i < values.length; i++) {
+                    String value = values[i];
+                    if (!StrUtil.hasEmpty(value)) {
+                        value = HtmlUtil.filter(value);
+                    }
+                    values[i] = value;
+                }
+                map.put(key, values);
+            }
+        }
+        return map;
+    }
+
+    @Override
+    public String getHeader(String name) {
+        String value = super.getHeader(name);
+        if (!StrUtil.hasEmpty(value)) {
+            value = HtmlUtil.filter(value);
+        }
+        return value;
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException {
+        InputStream in = super.getInputStream();
+        InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));
+        BufferedReader buffer = new BufferedReader(reader);
+        StringBuffer body = new StringBuffer();
+        String line = buffer.readLine();
+        while (line != null) {
+            body.append(line);
+            line = buffer.readLine();
+        }
+        buffer.close();
+        reader.close();
+        in.close();
+        Map<String, Object> map = JSONUtil.parseObj(body.toString());
+        Map<String, Object> result = new LinkedHashMap<>();
+        for (String key : map.keySet()) {
+            Object val = map.get(key);
+            if (val instanceof String) {
+                if (!StrUtil.hasEmpty(val.toString())) {
+                    result.put(key, HtmlUtil.filter(val.toString()));
+                }
+            } else {
+                result.put(key, val);
+            }
+        }
+        String json = JSONUtil.toJsonStr(result);
+        ByteArrayInputStream bain = new ByteArrayInputStream(json.getBytes());
+        return new ServletInputStream() {
+            @Override
+            public int read() throws IOException {
+                return bain.read();
+            }
+
+            @Override
+            public boolean isFinished() {
+                return false;
+            }
+
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+
+            }
+        };
+    }
+}

+ 7 - 0
src/main/java/com/imed/costaccount/mapper/DemoMapper.java

@@ -0,0 +1,7 @@
+package com.imed.costaccount.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.imed.costaccount.model.Demo;
+
+public interface DemoMapper extends BaseMapper<Demo> {
+}

+ 15 - 0
src/main/java/com/imed/costaccount/model/Demo.java

@@ -0,0 +1,15 @@
+package com.imed.costaccount.model;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+@TableName("demo")
+public class Demo {
+
+    private Integer id;
+
+    private String name;
+}

+ 7 - 0
src/main/java/com/imed/costaccount/service/DemoService.java

@@ -0,0 +1,7 @@
+package com.imed.costaccount.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.imed.costaccount.model.Demo;
+
+public interface DemoService extends IService<Demo> {
+}

+ 13 - 0
src/main/java/com/imed/costaccount/service/impl/DemoServiceImpl.java

@@ -0,0 +1,13 @@
+package com.imed.costaccount.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.imed.costaccount.mapper.DemoMapper;
+import com.imed.costaccount.model.Demo;
+import com.imed.costaccount.service.DemoService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class DemoServiceImpl extends ServiceImpl<DemoMapper, Demo> implements DemoService {
+
+
+}

+ 16 - 0
src/main/java/com/imed/costaccount/web/DemoController.java

@@ -0,0 +1,16 @@
+package com.imed.costaccount.web;
+
+import com.imed.costaccount.common.util.Result;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/demo")
+public class DemoController {
+
+    @GetMapping
+    public Result demo() {
+        return Result.ok();
+    }
+}

+ 3 - 1
src/main/resources/application.yml

@@ -1 +1,3 @@
-
+spring:
+  profiles:
+    active: dev

+ 0 - 13
src/test/java/com/imed/costaccount/CostAccountApplicationTests.java

@@ -1,13 +0,0 @@
-package com.imed.costaccount;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class CostAccountApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-}