Commit 697a2e5a authored by huangcb's avatar huangcb

Init

parents
/.idea/
*.iml
/target/
/log/
/logs/
\ No newline at end of file
#!/bin/bash
#这里可替换为你自己的执行程序,其他代码无需更改
APP_NAME=datacenter-cc-service.jar
#日志文件,与logback-spring.xml的日志文件保持一致
LOG_FILE=./logs/datacenter-cc-service.log
#日志配置文件
LOG_CONFIG_FILE=./logback-spring.xml
#使用说明,用来提示输入参数
usage() {
echo "Usage: sh 脚本名.sh [start|stop|restart|status]"
exit 1
}
#检查程序是否在运行
is_exist(){
pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
#如果不存在返回1,存在返回0
if [ -z "${pid}" ]; then
return 1
else
return 0
fi
}
#启动方法
start(){
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is already running. pid=${pid} ."
else
nohup java -Xmx128m -Xms128m -Dlogging.config=$LOG_CONFIG_FILE -jar $APP_NAME >> /dev/null 2>&1 &
date
tail -f $LOG_FILE
fi
}
#停止方法
stop(){
is_exist
if [ $? -eq "0" ]; then
kill -9 $pid
else
echo "${APP_NAME} is not running"
fi
}
#输出运行状态
status(){
is_exist
if [ $? -eq "0" ]; then
echo "${APP_NAME} is running. Pid is ${pid}"
else
echo "${APP_NAME} is NOT running."
fi
}
#重启
restart(){
stop
start
}
#根据输入参数,选择执行对应方法,不输入则执行使用说明
case "$1" in
"start")
start
;;
"stop")
stop
;;
"status")
status
;;
"restart")
restart
;;
*)
usage
;;
esac
\ No newline at end of file
<?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.1.1.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.esv.datacenter</groupId>
<artifactId>datacenter-cc-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>datacenter-cc-service</name>
<description>datacenter-cc-service</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
<alibaba-nacos-discovery.version>2.1.1.RELEASE</alibaba-nacos-discovery.version>
<alibaba-nacos-config.version>2.1.1.RELEASE</alibaba-nacos-config.version>
<alibaba-fastjson.version>1.2.70</alibaba-fastjson.version>
<alibaba-druid.version>1.1.22</alibaba-druid.version>
<apache-commons-lang3.version>3.7</apache-commons-lang3.version>
<mybatisplus.version>3.3.1</mybatisplus.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<version>${alibaba-nacos-discovery.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>${alibaba-nacos-config.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--lettuce pool连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${alibaba-fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${apache-commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatisplus.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${alibaba-druid.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>com.esv.platform</groupId>
<artifactId>esv-feign</artifactId>
<version>1.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.esv.platform</groupId>
<artifactId>gateway-common</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>esv-repository</id>
<url>http://192.168.31.249:18084/repository/maven-public/</url>
</repository>
</repositories>
<distributionManagement>
<snapshotRepository>
<id>esv-snapshots</id>
<name>esv-snapshots</name>
<url>http://192.168.31.249:18084/repository/maven-snapshots/</url>
</snapshotRepository>
<repository>
<id>esv-releases</id>
<name>esv-releases</name>
<url>http://192.168.31.249:18084/repository/maven-releases/</url>
</repository>
</distributionManagement>
<profiles>
<profile>
<id>develop</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>*.yml</exclude>
<exclude>*.properties</exclude>
<exclude>logback-spring.xml</exclude>
</excludes>
<filtering>true</filtering>
</resource>
</resources>
</build>
</profile>
</profiles>
<build>
<finalName>datacenter-cc-service</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
<nonFilteredFileExtension>eot</nonFilteredFileExtension>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>svg</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.esv.datacenter.cc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.request.RequestContextListener;
import javax.annotation.PostConstruct;
import java.util.TimeZone;
/**
* @description: 启动类
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/04/07 15:17
* @version:1.0
*/
@SpringBootApplication
@EnableDiscoveryClient
public class CCApplication {
public static void main(String[] args) {
SpringApplication.run(CCApplication.class, args);
}
@Bean
public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
@PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
}
}
package com.esv.datacenter.cc.common.cache;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "app.cache")
@Data
public class CacheNameConfig {
private List<CacheNameConfigItem> names = new ArrayList<>();
}
package com.esv.datacenter.cc.common.cache;
import lombok.Data;
//@Component
//@ConfigurationProperties(prefix = "app.cache.names")
@Data
public class CacheNameConfigItem {
private String key;
private Integer timeout;
}
package com.esv.datacenter.cc.common.cache;
/**
* description
* author chenfm
* createTime 2020/3/24 10:10
**/
public class CacheNames {
/**
* description 所有鉴权url
* author chenfm
* createTime 2020/4/10 14:16
**/
public static final String API_AUTHORITY = "freight-cc::apiAuthority";
/**
* description 用户信息
* author chenfm
* createTime 2020/4/10 14:16
**/
public static final String USER_INFO = "freight-cc::userInfo";
/**
* description 系统code对应系统信息
* author chenfm
* createTime 2020/4/10 14:16
**/
public static final String SYSTEM_BY_CODE = "freight-cc::systemByCode";
/**
* description 各系统用户权限
* author chenfm
* createTime 2020/4/10 14:16
**/
public static final String SYSTEM_USER_PERM = "freight-cc::systemUserPerm";
/**
* description 菜单信息
* author chenfm
* createTime 2020/4/10 14:16
**/
public static final String MENU_INFO = "freight-cc::menuInfo";
}
package com.esv.datacenter.cc.common.component;
import com.esv.datacenter.cc.util.EncryptUtils;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* 账号密码组件
*/
@Component
public class AccountPasswordComponent {
/**
* 创建简单密码加密盐
* @return
*/
public String getSimpleSalt() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
/**
* 生成DB存储的密码
* @param pwd 明文密码MD5加密后的密码
* @param salt
* @return
*/
public String generatePasswordDB(String pwd, String salt) {
return EncryptUtils.md5(pwd + salt);
}
}
package com.esv.datacenter.cc.common.component;
import com.esv.datacenter.cc.util.AESSecretUtil;
import com.esv.datacenter.cc.module.account.bo.TokenBO;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.HashMap;
import java.util.Map;
/**
* @description: JWT权限认证组件
* @author:hcbmailbox@163.com
* @date:2020/1/13
*/
@Component
@Slf4j
public class JwtAuthComponent {
@Value("${jwt.generate.key:HelloWorld}")
private String jwtGenerateKey;
@Value("${jwt.secret.key:HelloWorld}")
private String jwtSecretKey;
/**
* 生成JWT Token
* @param playloadMap
* @return
*/
public String generateJWT(Map<String, Object> playloadMap) {
JwtBuilder builder = Jwts.builder();
// 设置JWT头
Map<String, Object> headMap = new HashMap<>(2);
headMap.put("alg", SignatureAlgorithm.HS256.getValue());
headMap.put("typ", "JWT");
builder.setHeader(headMap);
// 设置有效载荷
builder.addClaims(playloadMap);
//签名算法,选择SHA-256
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//将BASE64SECRET常量字符串使用base64解码成字节数组
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(jwtGenerateKey);
//使用HmacSHA256签名算法生成一个HS256的签名秘钥Key
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
// 设置签名
builder.signWith(signatureAlgorithm, signingKey);
return builder.compact();
}
/**
* 创建Token
* @param playloadMap
* @return
*/
public String generateToken(Map<String, Object> playloadMap) {
// 创建JWT Token
String jwtToken = this.generateJWT(playloadMap);
// AES加密Token
String token = AESSecretUtil.encryptToStr(jwtToken, jwtSecretKey);
return token;
}
/**
* 解析Token
* @param jwtToken
* @return
*/
public Claims parseJWT(String jwtToken) {
Claims claims = null;
try {
if (StringUtils.isNotBlank(jwtToken)) {
//解析jwt
JwtParser jwtParser = Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(jwtGenerateKey));
claims = jwtParser.parseClaimsJws(jwtToken).getBody();
} else {
log.warn("jwtToken为空");
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return claims;
}
/**
* 获取Request请求Token
* @param request
* @return
*/
public String getRequestToken(HttpServletRequest request) {
String token = request.getHeader("Union-Authorization");
if (StringUtils.isEmpty(token)) {
return null;
}
if (!token.startsWith("Basic ")) {
return null;
}
return StringUtils.trimToNull(token.replaceFirst("Basic ", ""));
}
/**
* 判断请求Token是否有效
* @param request
* @return
*/
public boolean isValidRequestToken(HttpServletRequest request) {
String token = this.getRequestToken(request);
if (null == token) {
return false;
}
return isValidRequestToken(token);
}
/**
* 判断请求Token是否有效
* @param token
* @return
*/
public boolean isValidRequestToken(String token) {
String jwtToken = AESSecretUtil.decryptToStr(token, jwtSecretKey);
if (null == jwtToken) {
return false;
}
Claims claims = this.parseJWT(jwtToken);
if (null == claims) {
return false;
} else {
return true;
}
}
/**
* 解析Token数据
* @param token
* @return
*/
public TokenBO parseToken(String token) {
if (StringUtils.isEmpty(token)) {
return null;
}
Claims claims;
try {
String jwtToken = AESSecretUtil.decryptToStr(token, jwtSecretKey);
if (null == jwtToken) {
return null;
}
claims = this.parseJWT(jwtToken);
if (null == claims) {
return null;
}
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
TokenBO tokenBO = new TokenBO();
tokenBO.setUserId(Long.parseLong(String.valueOf(claims.get("userId"))));
tokenBO.setUserAccount((String) claims.get("userAccount"));
tokenBO.setType(Integer.parseInt(String.valueOf(claims.get("type"))));
tokenBO.setTenantId(Long.parseLong(String.valueOf(claims.get("tenantId"))));
tokenBO.setDepartmentId(Long.parseLong(String.valueOf(claims.get("departmentId"))));
tokenBO.setSource((String) claims.get("source"));
tokenBO.setIp((String) claims.get("ip"));
tokenBO.setCreateTime(Long.parseLong(String.valueOf(claims.get("createTime"))));
tokenBO.setExpireTime(Long.parseLong(String.valueOf(claims.get("expireTime"))));
tokenBO.setExtMap((Map<String, Object>) claims.get("extMap"));
return tokenBO;
}
/**
* 根据Token获取用户ID
* @param token
* @return
*/
public Long getUserId(String token) {
TokenBO tokenBO = this.parseToken(token);
if (null != tokenBO) {
return tokenBO.getUserId();
} else {
return null;
}
}
/**
* 根据Token获取用户帐号
* @param token
* @return
*/
public String getUserAccount(String token) {
TokenBO tokenBO = this.parseToken(token);
if (null != tokenBO) {
return tokenBO.getUserAccount();
} else {
return null;
}
}
}
package com.esv.datacenter.cc.common.component;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
@Component
@ManagedResource(
objectName = "com.esvtek.smartdata.authority:type=LoginMBean",
description = "登录次数统计"
)
public class LoginMBean {
private int count;
/**
* 暴露属性
*/
@ManagedAttribute(description = "这是登录次数")
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}
package com.esv.datacenter.cc.common.constants;
import com.esv.common.response.ECode;
/**
* @description:
* @author:hcbmailbox@163.com
* @date:2020/1/10
*/
public class ApiResponseCode extends ECode {
public static final ECode URL_REGISTERED = new ECode(1001, "未注册的URL");
public static final ECode NO_AUTHORITY = new ECode(1002, "没有API访问权限");
public static final ECode AUTH_TYPE_ERROR = new ECode(1003, "未定义的API权限类别");
public static final ECode SYSTEM_NOT_FOUND = new ECode(1004, "应用不存在");
public static final ECode CAPTCHA_ERROR = new ECode(1005, "验证码有误");
public ApiResponseCode(int code, String message) {
super(code, message);
}
}
package com.esv.datacenter.cc.common.constants;
/**
* @description:
* @project: freight-customer-service
* @name: com.esv.freight.customer.common.constants.CommonConstants
* @author: 黄朝斌
* @email: huangchaobin@esvtek.com
* @createTime: 2020/04/27 16:03
* @version:1.0
*/
public class CommonConstants {
/**
* 访问端来源:1-浏览器端、2-Android端、3-iOS端、4-后台服务端
**/
public static final String REQ_SOURCE_TYPE_KEY = "Source-Type";
public static final String REQ_SOURCE_TYPE_WEB = "1";
public static final String REQ_SOURCE_TYPE_ANDROID = "2";
public static final String REQ_SOURCE_TYPE_IOS = "3";
public static final String REQ_SOURCE_TYPE_SERVICE = "4";
/**
* Feign调用返回参数
**/
public static final String FEIGN_RESULT_CODE = "code";
public static final String FEIGN_RESULT_MESSAGE = "message";
public static final String FEIGN_RESULT_DATA = "data";
public static final int FEIGN_RESULT_SUCCESS = 200;
/**
* 字符串"null"
**/
public static final String NULL_STRING = "null";
/**
* 字符串"unknown"
**/
public static final String UNKNOWN_STRING = "unknown";
/**
* log日志输出的最大长度及截取输出的长度
**/
public static final int LOG_MAX_LENGTH = 5000;
public static final int LOG_CUT_LENGTH = 1000;
/**
* 默认字符编码
**/
public static final String DEFAULT_CHARACTER_ENCODING = "utf-8";
/**
* Http请求方式
**/
public static final String HTTP_REQUEST_METHOD_GET = "GET";
public static final String HTTP_REQUEST_METHOD_POST = "POST";
/**
* Http请求头
**/
public static final String HTTP_HEADER_X_FORWARDED_FOR = "x-forwarded-for";
public static final String HTTP_HEADER_PROXY_CLIENT_IP = "Proxy-Client-IP";
public static final String HTTP_HEADER_WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
}
package com.esv.datacenter.cc.common.constants;
/**
* 常量
*/
public class Constant {
public enum RoleType {
ALL_ADMIN(0),
TENANT_ADMIN(1),
GENERAL(2);
private Integer value;
RoleType(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
}
public enum UserType {
PLATFORM_ADMIN(0),
TENANT_ADMIN(1),
GENERAL(2);
private Integer value;
UserType(Integer value) {
this.value = value;
}
public Integer getValue() {
return value;
}
}
}
/**
* Copyright (c) 2016-2019 人人开源 All rights reserved.
*
* https://www.renren.io
*
* 版权所有,侵权必究!
*/
package com.esv.datacenter.cc.common.exception;
/**
* 自定义异常
*
* @author Mark sunlightcs@gmail.com
*/
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
package com.esv.datacenter.cc.common.filter;
import com.esv.datacenter.cc.common.constants.CommonConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.UUID;
/**
* @description: 设置Logback线程唯一ID
* @author:hcbmailbox@163.com
* @date:2020/1/8
*/
@Slf4j
public class LogbackFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
// 获取来自上游服务的传参traceId
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String traceId = httpServletRequest.getHeader("gateway_traceid");
if (StringUtils.isBlank(traceId)) {
traceId = httpServletRequest.getHeader("trace_id");
}
boolean bInsertMDC = setMDC(traceId);
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
if(bInsertMDC) {
MDC.remove("traceId");
}
}
}
private boolean setMDC(String traceId) {
if (StringUtils.isEmpty(traceId) || CommonConstants.NULL_STRING.equalsIgnoreCase(traceId)) {
traceId = UUID.randomUUID().toString().replace("-", "");
}
MDC.put("traceId", traceId);
return true;
}
}
package com.esv.datacenter.cc.common.filter;
import com.alibaba.fastjson.JSONObject;
import com.esv.datacenter.cc.common.constants.CommonConstants;
import com.esv.datacenter.cc.common.wrapper.RestRequestWrapper;
import com.esv.datacenter.cc.common.wrapper.RestResponseWrapper;
import com.esv.datacenter.cc.util.ReqUtils;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
/**
* @description: 请求日志输出Filter
* @author:hcbmailbox@163.com
* @date:2020/1/8
*/
@Slf4j
public class RestLogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
RestRequestWrapper requestWrapper = new RestRequestWrapper((HttpServletRequest)servletRequest);
RestResponseWrapper responseWrapper = new RestResponseWrapper((HttpServletResponse) servletResponse);
// 日志输出请求体
this.logReq(requestWrapper);
// 日志输出请求头
this.logReqHeader(requestWrapper);
filterChain.doFilter(requestWrapper, responseWrapper);
// 日志输出返回体
this.logRes(responseWrapper);
}
/**
* 日志输出请求体
**/
private void logReq(RestRequestWrapper requestWrapper) {
String url = requestWrapper.getRequestURI();
String method = requestWrapper.getMethod();
String reqBody = "";
// 获取get、post请求体
if (CommonConstants.HTTP_REQUEST_METHOD_GET.equalsIgnoreCase(method)) {
Enumeration em = requestWrapper.getParameterNames();
while (em.hasMoreElements()) {
String k = em.nextElement().toString();
String v = requestWrapper.getParameter(k);
reqBody += "&" + k + "=" + v;
}
reqBody = reqBody.replaceFirst("&", "");
} else if (CommonConstants.HTTP_REQUEST_METHOD_POST.equalsIgnoreCase(method)) {
reqBody = ReqUtils.getPostBody(requestWrapper);
}
// 请求体日志截取
if (CommonConstants.LOG_MAX_LENGTH < reqBody.length()) {
reqBody = reqBody.substring(0, CommonConstants.LOG_CUT_LENGTH) + "……";
}
// 日志输出请求体
log.info("[IP={}]收到{}请求,url:{},body:{}", ReqUtils.getHttpClientIp(requestWrapper), method, url, reqBody);
}
/**
* 日志输出请求头
**/
private void logReqHeader(RestRequestWrapper request) {
JSONObject headerJson = new JSONObject();
Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
headerJson.put(key, request.getHeader(key));
}
log.info("请求头:{}", headerJson.toJSONString());
}
/**
* 日志输出返回体
**/
private void logRes(RestResponseWrapper responseWrapper) {
byte[] bytes = responseWrapper.getBody();
String resBody = null;
try {
resBody = new String(bytes, CommonConstants.DEFAULT_CHARACTER_ENCODING);
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
}
log.info("请求响应:{}", resBody);
}
}
package com.esv.datacenter.cc.common.form;
import javax.validation.groups.Default;
public interface Add extends Default {
}
package com.esv.datacenter.cc.common.form;
import javax.validation.groups.Default;
/**
* @description:
* @project: esv-cc
* @name: Delete
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/3/17 14:11
* @version:1.0
*/
public interface Delete extends Default {
}
package com.esv.datacenter.cc.common.form;
import javax.validation.groups.Default;
public interface List extends Default {
}
package com.esv.datacenter.cc.common.form;
import javax.validation.groups.Default;
public interface Update extends Default {
}
package com.esv.datacenter.cc.common.handler;
import com.esv.common.response.EResponse;
import com.esv.datacenter.cc.common.constants.ApiResponseCode;
import com.esv.datacenter.cc.common.exception.RRException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;
/**
* @description: Rest请求异常处理Handler
* @author:hcbmailbox@163.com
* @date:2020/1/8
*/
@Slf4j
@RestControllerAdvice
@ControllerAdvice
public class RestExceptionHandler {
@ExceptionHandler(value = Exception.class)
public EResponse defaultErrorHandler(HttpServletRequest req, Exception e) {
EResponse eResponse;
if (e instanceof RRException) {
eResponse = EResponse.error().message(((RRException) e).getMsg());
} else if (e instanceof MethodArgumentNotValidException) {
String message = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("|"));
eResponse = EResponse.error(ApiResponseCode.PARAM_ERROR).message(message);
} else if (e instanceof ConstraintViolationException) {
String message = e.getMessage();
if (message.contains(":")) {
message = message.split(":")[1];
}
eResponse = EResponse.error(ApiResponseCode.PARAM_ERROR).message("参数错误:" + message);
} else if (e instanceof MissingServletRequestParameterException) {
eResponse = EResponse.error(ApiResponseCode.PARAM_ERROR);
} else {
eResponse = EResponse.error();
log.error(e.getMessage(), e);
}
return eResponse;
}
}
package com.esv.datacenter.cc.common.wrapper;
import lombok.extern.slf4j.Slf4j;
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;
/**
* @description:
* @author:hcbmailbox@163.com
* @date:2020/1/8
*/
@Slf4j
public class RestRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
public RestRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
ServletInputStream inputStream = request.getInputStream();
if (null != inputStream) {
body = readBytes(inputStream);
}
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() {
return bais.read();
}
};
}
private String streamToString(InputStream inputStream) {
try (BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"))) {
StringBuilder builder = new StringBuilder();
String output;
while ((output = br.readLine()) != null) {
builder.append(output);
}
return builder.toString();
} catch (IOException e) {
throw new RuntimeException("Http 服务调用失败", e);
}
}
private byte[] readBytes(ServletInputStream inputStream) {
return streamToString(inputStream).getBytes(Charset.forName("UTF-8"));
}
public void setBody(String data) {
this.body = data.getBytes(Charset.forName("UTF-8"));
}
}
package com.esv.datacenter.cc.common.wrapper;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
/**
* @description:
* @author:hcbmailbox@163.com
* @date:2020/1/8
*/
public class RestResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
private HttpServletResponse response;
public RestResponseWrapper(HttpServletResponse response) {
super(response);
this.response = response;
}
public byte[] getBody() {
return byteArrayOutputStream.toByteArray();
}
@Override
public ServletOutputStream getOutputStream() {
return new ServletOutputStreamWrapper(this.byteArrayOutputStream , this.response);
}
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(new OutputStreamWriter(this.byteArrayOutputStream , this.response.getCharacterEncoding()));
}
@Data
@AllArgsConstructor
private static class ServletOutputStreamWrapper extends ServletOutputStream {
private ByteArrayOutputStream outputStream;
private HttpServletResponse response;
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener listener) {
}
@Override
public void write(int b) throws IOException {
this.outputStream.write(b);
}
@Override
public void flush() throws IOException {
if (! this.response.isCommitted()) {
byte[] body = this.outputStream.toByteArray();
ServletOutputStream outputStream = this.response.getOutputStream();
outputStream.write(body);
outputStream.flush();
}
}
}
}
package com.esv.datacenter.cc.config;
import com.esv.datacenter.cc.common.cache.CacheNameConfig;
import com.esv.datacenter.cc.common.cache.CacheNameConfigItem;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Configuration
@EnableCaching
public class CacheConfig {
@Autowired
CacheNameConfig cacheNameConfig;
/*
@Bean
public CacheManager redisCacheManager(RedisTemplate<String, Object> template) {
RedisCacheManager redisCacheManager = new RedisCacheManager(template);
//long expirationDefault = Long.valueOf(bossBaseProperties().getExpirationDefault());
long expirationDefault = Long.valueOf(300);
redisCacheManager.setDefaultExpiration(expirationDefault);
//String allExpiration = bossBaseProperties().getExpiration();
String allExpiration = "dealer:60,sim:10";
if (allExpiration != null && !"".equals(allExpiration)) {
Map<String, Long> expiresMap = new HashMap<>();
String[] expirations = allExpiration.split(",");
for (String expiration : expirations) {
String[] pairs = expiration.split(":");
String cacheName = pairs[0];
long expirationValue = Long.valueOf(pairs[1]);
expiresMap.put(cacheName, expirationValue);
redisCacheManager.setExpires(expiresMap);
}
}
return redisCacheManager;
}
*/
/**
* 申明缓存管理器,会创建一个切面(aspect)并触发Spring缓存注解的切点(pointcut)
* 根据类或者方法所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,将数据添加到缓存之中或者从缓存中移除某个值
* @return
*/
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// return RedisCacheManager.create(redisConnectionFactory);
return new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
this.getRedisCacheConfigurationWithTtl(600),//默认策略,未配置的key会使用这个
this.getRedisCacheConfigurationMap() //指定key策略
);
}
private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
List<CacheNameConfigItem> names = cacheNameConfig.getNames();
for (CacheNameConfigItem item : names) {
// 需要作缓存在这里加上就加一个put即可
redisCacheConfigurationMap.put(item.getKey(), this.getRedisCacheConfigurationWithTtl(item.getTimeout()));
}
return redisCacheConfigurationMap;
}
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(jsonSerializer())
).entryTtl(Duration.ofSeconds(seconds));
return redisCacheConfiguration;
}
/**
* RedisTemplate默认使用的序列化机制是JdkSerializationRedisSerializer,这里我们是用Jackson2JsonRedisSerializer
* @return
*/
private RedisSerializer jsonSerializer() {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
return jackson2JsonRedisSerializer;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
// 创建一个模板类
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
// 将刚才的redis连接工厂设置到模板类中
template.setConnectionFactory(factory);
// 设置key的序列化器
template.setKeySerializer(new StringRedisSerializer());
// 设置value的序列化器
//使用Jackson 2,将对象序列化为JSON
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//json转对象类,不设置默认的会将json转成hashmap
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
package com.esv.datacenter.cc.config;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.config.FeignClientConfig
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/17 9:59
* @version: 1.0
*/
@Configuration
@EnableFeignClients(value = {"com.esv.datacenter.cc.feign.client"})
public class FeignClientConfig {
}
package com.esv.datacenter.cc.config;
import com.esv.datacenter.cc.common.filter.LogbackFilter;
import com.esv.datacenter.cc.common.filter.RestLogFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @description: 注册请求Filter
* @author:hcbmailbox@163.com
* @date:2020/1/8
*/
@Configuration
public class FilterConfig {
private static final String URL = "/*";
@Bean
public LogbackFilter getLogbackFilter() {
return new LogbackFilter();
}
@Bean
public RestLogFilter getRestLogFilter() {
return new RestLogFilter();
}
@Bean
public FilterRegistrationBean<LogbackFilter> logbackFilterRegister() {
FilterRegistrationBean<LogbackFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(getLogbackFilter());
registration.addUrlPatterns(URL);
registration.setOrder(1);
return registration;
}
@Bean
public FilterRegistrationBean<RestLogFilter> restLogFilterRegister() {
FilterRegistrationBean<RestLogFilter> filterRegistrationBean=new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(getRestLogFilter());
filterRegistrationBean.addUrlPatterns(URL);
filterRegistrationBean.setOrder(2);
return filterRegistrationBean;
}
}
package com.esv.datacenter.cc.config.mybatis;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.esv.datacenter.cc.util.ReqUtils;
import com.esv.gateway.common.DataPermsType;
import com.esv.gateway.common.GatewayHeaders;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.schema.Column;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.config.mybatis.DataPermHandler
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/7 19:27
* @version:1.0
*/
public class DataPermHandler implements TenantHandler {
private final List<String> filterTableNames = Arrays.asList(
"cc_api_authority", "cc_tenant", "cc_department", "cc_system", "cc_menu",
"cc_role_menu", "cc_user_role", "cc_user",
"cc_user_login_info", "cc_captcha", "cc_config"
);
@Override
public Expression getTenantId(boolean where) {
String dataPerm = ReqUtils.getRequestHeader(GatewayHeaders.DATA_PERM);
//这里只是演示切换单个tenantId和多个tenantId
final boolean multipleTenantIds = DataPermsType.DATA_PERM_DEPARTMENT.equals(dataPerm);
//具体场景,可以根据情况来拼接
if (where && multipleTenantIds) {
//演示如何实现tenant_id in (1,2)
return multipleTenantIdCondition();
} else {
return singleTenantIdCondition();
}
}
// 获取tenantId
private Expression singleTenantIdCondition() {
String tenantId = ReqUtils.getRequestHeader(GatewayHeaders.TENANT_ID);
return new LongValue(tenantId);
}
// 获取departmentId
private Expression multipleTenantIdCondition() {
String departmentChildren = ReqUtils.getRequestHeader(GatewayHeaders.DEPARTMENT_CHILDREN);
final InExpression inExpression = new InExpression();
inExpression.setLeftExpression(new Column(getTenantIdColumn()));
final ExpressionList itemsList = new ExpressionList();
final List<Expression> inValues = new ArrayList<>();
for (String departmentId : departmentChildren.split(",")) {
inValues.add(new LongValue(departmentId));
}
// inValues.add(new LongValue(1));//ID自己想办法获取到
itemsList.setExpressions(inValues);
inExpression.setRightItemsList(itemsList);
return inExpression;
}
@Override
public String getTenantIdColumn() {
String dataPerm = ReqUtils.getRequestHeader(GatewayHeaders.DATA_PERM);
//这里只是演示切换单个tenantId和多个tenantId
final boolean multipleTenantIds = DataPermsType.DATA_PERM_DEPARTMENT.equals(dataPerm);
if (multipleTenantIds) {
return "department_id";
}
return "tenant_id";
}
/**
* description 判断是否过滤表
* param [tableName]
* return boolean
* author chenfm
* createTime 2020/4/8 9:31
**/
@Override
public boolean doTableFilter(String tableName) {
// 只有查询时添加条件
if (tableName.endsWith("|select")) {
tableName = tableName.replace("|select", "");
} else {
return true;
}
if (filterTableNames.contains(tableName)) {
return true;
}
// 全局数据权限不加入条件
String dataPerm = ReqUtils.getRequestHeader(GatewayHeaders.DATA_PERM);
if (DataPermsType.DATA_PERM_ALL.equals(dataPerm)) {
return true;
}
return false;
}
}
package com.esv.datacenter.cc.config.mybatis;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.*;
import java.util.List;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.config.mybatis.DataPermParser
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/7 17:00
* @version:1.0
*/
@Slf4j
public class DataPermParser extends TenantSqlParser {
/**
* 目前仅支持:in, between, >, <, =, !=等比较操作,处理多租户的字段加上表别名
*
* @param expression
* @param table
* @return
*/
protected Expression processTableAlias(Expression expression, Table table) {
String tableAliasName;
if (table.getAlias() == null) {
tableAliasName = table.getName();
} else {
tableAliasName = table.getAlias().getName();
}
if (expression instanceof InExpression) {
InExpression in = (InExpression) expression;
if (in.getLeftExpression() instanceof Column) {
setTableAliasNameForColumn((Column) in.getLeftExpression(), tableAliasName);
}
} else if (expression instanceof BinaryExpression) {
BinaryExpression compare = (BinaryExpression) expression;
if (compare.getLeftExpression() instanceof Column) {
setTableAliasNameForColumn((Column) compare.getLeftExpression(), tableAliasName);
} else if (compare.getRightExpression() instanceof Column) {
setTableAliasNameForColumn((Column) compare.getRightExpression(), tableAliasName);
}
} else if (expression instanceof Between) {
Between between = (Between) expression;
if (between.getLeftExpression() instanceof Column) {
setTableAliasNameForColumn((Column) between.getLeftExpression(), tableAliasName);
}
}
return expression;
}
private void setTableAliasNameForColumn(Column column, String tableAliasName) {
column.setColumnName(tableAliasName + "." + column.getColumnName());
}
/**
* 默认是按 tenant_id=1 按等于条件追加
*
* @param currentExpression 现有的条件:比如你原来的sql查询条件
* @param table
* @return
*/
@Override
protected Expression builderExpression(Expression currentExpression, Table table) {
final Expression tenantExpression = this.getTenantHandler().getTenantId(true);
Expression appendExpression;
if (!(tenantExpression instanceof SupportsOldOracleJoinSyntax)) {
appendExpression = new EqualsTo();
((EqualsTo) appendExpression).setLeftExpression(this.getAliasColumn(table));
((EqualsTo) appendExpression).setRightExpression(tenantExpression);
} else {
appendExpression = processTableAlias(tenantExpression, table);
}
if (currentExpression == null) {
return appendExpression;
}
if (currentExpression instanceof BinaryExpression) {
BinaryExpression binaryExpression = (BinaryExpression) currentExpression;
if (binaryExpression.getLeftExpression() instanceof FromItem) {
processFromItem((FromItem) binaryExpression.getLeftExpression());
}
if (binaryExpression.getRightExpression() instanceof FromItem) {
processFromItem((FromItem) binaryExpression.getRightExpression());
}
} else if (currentExpression instanceof InExpression) {
InExpression inExp = (InExpression) currentExpression;
ItemsList rightItems = inExp.getRightItemsList();
if (rightItems instanceof SubSelect) {
processSelectBody(((SubSelect) rightItems).getSelectBody());
}
}
if (currentExpression instanceof OrExpression) {
return new AndExpression(new Parenthesis(currentExpression), appendExpression);
} else {
return new AndExpression(currentExpression, appendExpression);
}
}
@Override
protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) {
FromItem fromItem = plainSelect.getFromItem();
if (fromItem instanceof Table) {
Table fromTable = (Table) fromItem;
if (!this.getTenantHandler().doTableFilter(fromTable.getName() + "|select")) {
plainSelect.setWhere(builderExpression(plainSelect.getWhere(), fromTable));
if (addColumn) {
plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(this.getTenantHandler().getTenantIdColumn())));
}
}
} else {
processFromItem(fromItem);
}
List<Join> joins = plainSelect.getJoins();
if (joins != null && joins.size() > 0) {
joins.forEach(j -> {
processJoin(j);
processFromItem(j.getRightItem());
});
}
}
}
package com.esv.datacenter.cc.config.mybatis;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.esv.datacenter.cc.util.ReqUtils;
import com.esv.gateway.common.GatewayHeaders;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.config.mybatis.MetaHandler
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/7 20:15
* @version:1.0
*/
@Slf4j
@Component
public class EsvMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
if (metaObject.hasSetter("createUser")) {
String userAccount = ReqUtils.getRequestHeader(GatewayHeaders.USER_ACCOUNT);
this.setFieldValByName("createUser", userAccount, metaObject);
}
if (metaObject.hasSetter("createTime")) {
this.setFieldValByName("createTime", new Date(), metaObject);
}
if (metaObject.hasSetter("tenantId") && metaObject.getValue("tenantId") == null) {
String tenantId = ReqUtils.getRequestHeader(GatewayHeaders.TENANT_ID);
this.setFieldValByName("tenantId", Long.parseLong(tenantId), metaObject);
}
if (metaObject.hasSetter("departmentId") && metaObject.getValue("departmentId") == null) {
String departmentId = ReqUtils.getRequestHeader(GatewayHeaders.DEPARTMENT_ID);
this.setFieldValByName("departmentId", Long.parseLong(departmentId), metaObject);
}
}
@Override
public void updateFill(MetaObject metaObject) {
if (metaObject.hasSetter("updateUser")) {
String userAccount = ReqUtils.getRequestHeader(GatewayHeaders.USER_ACCOUNT);
this.setFieldValByName("updateUser", userAccount, metaObject);
}
if (metaObject.hasSetter("updateTime")) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
}
package com.esv.datacenter.cc.config.mybatis;
import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* mybatis-plus配置
*
* @author lijd
* @date 2020/1/7
*/
@Configuration
@MapperScan({"com.esv.datacenter.cc.module.*.dao"})
public class MybatisPlusConfig {
/**
* 分页插件
*/
// @Bean
// public PaginationInterceptor paginationInterceptor() {
// return new PaginationInterceptor();
// }
/**
* 多租户属于 SQL 解析部分,依赖 MP 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
/*
* 【测试多租户】 SQL 解析处理拦截器<br>
* 这里固定写成住户 1 实际情况你可以从cookie读取,因此数据看不到 【 麻花藤 】 这条记录( 注意观察 SQL )<br>
*/
List<ISqlParser> sqlParserList = new ArrayList<>();
TenantSqlParser tenantSqlParser = new DataPermParser();
tenantSqlParser.setTenantHandler(new DataPermHandler());
sqlParserList.add(tenantSqlParser);
paginationInterceptor.setSqlParserList(sqlParserList);
// paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
// @Override
// public boolean doFilter(MetaObject metaObject) {
// MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
// // 过滤自定义查询此时无租户信息约束【 麻花藤 】出现
// if ("com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId())) {
// return true;
// }
// return false;
// }
// });
return paginationInterceptor;
}
}
package com.esv.datacenter.cc.feign.client;
import com.alibaba.fastjson.JSONObject;
import com.esv.datacenter.cc.feign.req.CaptchaVerifyReq;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.feign.client.captchaFeignClient
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/17 10:00
* @version: 1.0
*/
@FeignClient("datacenter-base-service")
@RequestMapping("base")
public interface CaptchaFeignClient {
@PostMapping("captcha/verify")
JSONObject captchaVerify(CaptchaVerifyReq captchaVerifyReq);
}
package com.esv.datacenter.cc.feign.req;
import lombok.Data;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.feign.req.CaptchaVerifyReq
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/17 10:02
* @version: 1.0
*/
@Data
public class CaptchaVerifyReq {
private String id;
private String captcha;
public CaptchaVerifyReq() {
}
public CaptchaVerifyReq(String id, String captcha) {
this.id = id;
this.captcha = captcha;
}
}
package com.esv.datacenter.cc.feign.res;
import lombok.Data;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.feign.res.CaptchaVerifyRes
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/17 10:04
* @version: 1.0
*/
@Data
public class CaptchaVerifyRes {
private Boolean result;
}
package com.esv.datacenter.cc.form;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class IdForm {
@NotNull
private Long id;
}
package com.esv.datacenter.cc.module.account.bo;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.Map;
/**
* @description:
* @author:hcbmailbox@163.com
* @date:2020/1/17
*/
@Data
public class TokenBO {
/**
* 来源:web/android/ios/hu/api
*/
private String source;
/**
* description 创建时间
* author chenfm
* createTime 2020/4/4 13:18
**/
private Long createTime;
/**
* description 过期时间
* author chenfm
* createTime 2020/4/4 13:18
**/
private Long expireTime;
/**
* description 用户id
* author chenfm
* createTime 2020/4/4 13:18
**/
private Long userId;
/**
* description 用户账号
* author chenfm
* createTime 2020/4/4 13:18
**/
private String userAccount;
/**
* description 0-平台管理员, 1-租户管理员, 2-普通用户
* author chenfm
* createTime 2020/4/9 19:37
**/
private Integer type;
/**
* description 租户id
* author chenfm
* createTime 2020/4/4 13:18
**/
private Long tenantId;
/**
* description 部门id
* author chenfm
* createTime 2020/4/4 13:20
**/
private Long departmentId;
/**
* description 请求ip
* author chenfm
* createTime 2020/4/4 13:18
**/
private String ip;
/**
* description 扩展字段
* author chenfm
* createTime 2020/4/4 13:19
**/
private Map<String, Object> extMap;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}
package com.esv.datacenter.cc.module.account.controller;
import com.alibaba.fastjson.JSONObject;
import com.esv.datacenter.cc.common.component.LoginMBean;
import com.esv.datacenter.cc.common.component.JwtAuthComponent;
import com.esv.datacenter.cc.common.constants.ApiResponseCode;
import com.esv.datacenter.cc.feign.client.CaptchaFeignClient;
import com.esv.datacenter.cc.feign.req.CaptchaVerifyReq;
import com.esv.datacenter.cc.feign.res.CaptchaVerifyRes;
import com.esv.datacenter.cc.module.account.bo.TokenBO;
import com.esv.datacenter.cc.module.account.dto.UserLoginInfoDTO;
import com.esv.datacenter.cc.module.account.dto.UserSystemDTO;
import com.esv.datacenter.cc.module.account.form.AccountForm;
import com.esv.datacenter.cc.module.account.service.AccountService;
import com.esv.datacenter.cc.module.account.service.UserLoginInfoService;
import com.esv.datacenter.cc.module.account.vo.LoginVO;
import com.esv.datacenter.cc.module.system.service.SystemService;
import com.esv.datacenter.cc.util.ReqUtils;
import com.esv.common.response.ECode;
import com.esv.common.response.EResponse;
import com.esv.common.response.R;
import com.esv.gateway.common.GatewayHeaders;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description: 帐号服务Controller
* @author:hcbmailbox@163.com
* @date:2020/1/15
*/
@RestController
@RequestMapping("account")
@Slf4j
public class AccountController {
private CaptchaFeignClient captchaFeignClient;
private JwtAuthComponent jwtAuthComponent;
private AccountService accountService;
private UserLoginInfoService userLoginInfoService;
private HttpServletRequest request;
private LoginMBean loginMBean;
private SystemService systemService;
@Autowired
public AccountController(CaptchaFeignClient captchaFeignClient, JwtAuthComponent jwtAuthComponent,
AccountService accountService,
UserLoginInfoService userLoginInfoService, HttpServletRequest request,
LoginMBean loginMBean, SystemService systemService) {
this.captchaFeignClient = captchaFeignClient;
this.jwtAuthComponent = jwtAuthComponent;
this.accountService = accountService;
this.userLoginInfoService = userLoginInfoService;
this.request = request;
this.loginMBean = loginMBean;
this.systemService = systemService;
}
/**
* 帐号密码登录
* @return
* @throws Exception
*/
@PostMapping("loginByAccountPwd")
public EResponse<LoginVO> loginByAccountPwd(HttpServletRequest request, @RequestBody @Validated AccountForm form) {
CaptchaVerifyReq captchaVerifyReq = new CaptchaVerifyReq(form.getId(), form.getCaptcha());
JSONObject json = captchaFeignClient.captchaVerify(captchaVerifyReq);
CaptchaVerifyRes captchaVerifyRes = json.getObject("data", CaptchaVerifyRes.class);
if (!captchaVerifyRes.getResult()) {
return EResponse.error(ApiResponseCode.CAPTCHA_ERROR);
}
Map<String, Object> extMap = new HashMap<>(1);
extMap.put("ip", StringUtils.trimToEmpty(ReqUtils.getHttpClientIp(request)));
String token = accountService.loginByAccountPwd(form.getAccount(), form.getPassword(), extMap);
LoginVO loginVO = new LoginVO();
loginVO.setToken(token);
try {
loginMBean.setCount(loginMBean.getCount() + 1);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return EResponse.ok(loginVO);
}
/**
* 帐号登出
* @return
* @throws Exception
*/
@PostMapping("logout")
public EResponse logout() {
String token = jwtAuthComponent.getRequestToken(this.request);
TokenBO tokenBO = jwtAuthComponent.parseToken(token);
if (null == tokenBO) {
return EResponse.error(ECode.TOKEN_INVALID);
} else {
accountService.logout(tokenBO);
return EResponse.ok();
}
}
/**
* Token有效性校验
* @param request
* @return
* @throws Exception
*/
@GetMapping("checkToken")
public EResponse checkToken(HttpServletRequest request) {
String token = jwtAuthComponent.getRequestToken(request);
if (StringUtils.isEmpty(token)) {
return EResponse.error(ECode.TOKEN_INVALID);
}
TokenBO tokenBO = jwtAuthComponent.parseToken(token);
if (null == tokenBO) {
return EResponse.error(ECode.TOKEN_INVALID);
}
if (0L != tokenBO.getExpireTime() && System.currentTimeMillis() > tokenBO.getExpireTime()) {
return EResponse.error(ECode.TOKEN_EXPIRED);
}
return EResponse.ok();
}
/**
* 获取用户登录信息
* @param userId
* @return
*/
@GetMapping("getUserLoginInfo")
public R getUserLoginInfo(@RequestHeader(GatewayHeaders.TENANT_ID) Long tenantId,
@RequestHeader(GatewayHeaders.USER_ID) Long userId) {
UserLoginInfoDTO userLoginInfoDTO = userLoginInfoService.getUserLoginInfo(tenantId, userId);
List<UserSystemDTO> userSystemList = systemService.userSystemList(tenantId, userId);
userLoginInfoDTO.setUserSystemList(userSystemList);
return R.ok(userLoginInfoDTO);
}
}
package com.esv.datacenter.cc.module.account.controller;
import com.esv.datacenter.cc.common.component.LoginMBean;
import com.esv.common.response.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("jmx")
public class JmxController {
private LoginMBean loginMBean;
@Autowired
public JmxController(LoginMBean loginMBean) {
this.loginMBean = loginMBean;
}
@RequestMapping(value = "loginCount", method = RequestMethod.GET)
public R loginCount(@RequestParam(value = "count", required = false) Integer count) {
if (count != null) {
loginMBean.setCount(count);
}
return R.ok().put("count", loginMBean.getCount());
}
}
package com.esv.datacenter.cc.module.account.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.esv.datacenter.cc.module.account.entity.UserLoginInfoEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 帐号登录信息表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-20 09:52:11
*/
@Mapper
public interface UserLoginInfoDao extends BaseMapper<UserLoginInfoEntity> {
}
package com.esv.datacenter.cc.module.account.dto;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.util.List;
/**
* @description: 用户登录信息
* @author:hcbmailbox@163.com
* @date:2020/1/20
*/
@Data
public class UserLoginInfoDTO {
private Long userId;
private String account;
private String realName;
private String email;
private String mobile;
private String departmentName;
private String roleName;
/**
* 状态:0-已登录、1-已登出
*/
private String status;
private String loginIp;
private Long loginTime;
private Long logoutTime;
private String lastLoginIp;
private Long lastLoginTime;
/**
* 用户可访问系统
*/
private List<UserSystemDTO> userSystemList;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}
package com.esv.datacenter.cc.module.account.dto;
import com.esv.datacenter.cc.module.system.entity.SystemEntity;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class UserSystemDTO {
/**
* 系统id
*/
private Long id;
/**
* 系统标识编码
*/
private String systemCode;
/**
* 系统名称
*/
private String systemName;
/**
* 系统图标
*/
private String icon;
/**
* 系统url
*/
private String url;
/**
* 开发url
*/
private String devUrl;
/**
* 状态 0:正常/1:锁定
*/
private Integer status;
/**
* 系统权限列表
*/
private List<UserSystemRoleDTO> userSystemRoleList;
public UserSystemDTO() {
}
public UserSystemDTO(SystemEntity systemEntity) {
this.id = systemEntity.getId();
this.systemCode = systemEntity.getSystemCode();
this.systemName = systemEntity.getSystemName();
this.icon = systemEntity.getIcon();
this.url = systemEntity.getUrl();
this.devUrl = systemEntity.getDevUrl();
this.status = systemEntity.getStatus();
userSystemRoleList = new ArrayList<>();
}
}
package com.esv.datacenter.cc.module.account.dto;
import lombok.Data;
@Data
public class UserSystemRoleDTO {
/**
* 角色id
*/
private Long id;
/**
* 角色名称
*/
private String roleName;
public UserSystemRoleDTO() {
}
public UserSystemRoleDTO(Long id, String roleName) {
this.id = id;
this.roleName = roleName;
}
}
package com.esv.datacenter.cc.module.account.entity;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.io.Serializable;
import java.util.Date;
/**
* 帐号登录信息表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-20 09:52:11
*/
@Data
@TableName("cc_user_login_info")
public class UserLoginInfoEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId
private Long id;
/**
* 用户ID
*/
private Long userId;
/**
* 登录IP
*/
private String ip;
/**
* Token
*/
private String token;
/**
* 状态:0-已登录、1-已登出
*/
private String status;
/**
* 登录时间
*/
private Date loginTime;
/**
* description 上次登录ip
* author chenfm
* createTime 2020/3/16 16:20
**/
private String lastIp;
/**
* description 上次登录时间
* author chenfm
* createTime 2020/3/16 16:20
**/
private Date lastLoginTime;
/**
* 登出时间
*/
@TableField(updateStrategy = FieldStrategy.IGNORED)
private Date logoutTime;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}
package com.esv.datacenter.cc.module.account.form;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotEmpty;
/**
* @description:
* @author:hcbmailbox@163.com
* @date:2020/1/13
*/
@Data
public class AccountForm {
@NotEmpty(message="验证码id不能为空")
private String id;
@NotEmpty(message="验证码不能为空")
private String captcha;
/**
* 用户名
*/
@Length(max = 50, message = "账号长度不合法")
@NotEmpty(message="账号不能为空")
private String account;
/**
* 密码
*/
@Length(min = 32, max = 32, message = "密码长度不合法")
@NotEmpty(message = "密码不能为空")
private String password;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
}
}
package com.esv.datacenter.cc.module.account.service;
import com.esv.datacenter.cc.module.account.bo.TokenBO;
import java.util.Map;
/**
* 帐户中心接口类
*/
public interface AccountService {
/**
* 账号密码登录
* @param account
* @param pwd
* @param extMap
* @return
*/
String loginByAccountPwd(String account, String pwd, Map<String, Object> extMap);
/**
* 使用token执行登出操作
* @param tokenBO
*/
void logout(TokenBO tokenBO);
}
package com.esv.datacenter.cc.module.account.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.esv.datacenter.cc.module.account.dto.UserLoginInfoDTO;
import com.esv.datacenter.cc.module.account.entity.UserLoginInfoEntity;
/**
* 帐号登录信息表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-20 09:52:11
*/
public interface UserLoginInfoService extends IService<UserLoginInfoEntity> {
/**
* 获取用户登录信息
* @param userId
* @return
*/
UserLoginInfoDTO getUserLoginInfo(Long tenantId, Long userId);
/**
* 保存登录/登出信息
* @param loginInfoEntity
* @return
*/
int saveLoginInfo(UserLoginInfoEntity loginInfoEntity);
}
package com.esv.datacenter.cc.module.account.service.impl;
import com.esv.datacenter.cc.module.account.entity.UserLoginInfoEntity;
import com.esv.datacenter.cc.module.account.service.AccountService;
import com.esv.datacenter.cc.module.account.service.UserLoginInfoService;
import com.esv.datacenter.cc.common.component.AccountPasswordComponent;
import com.esv.datacenter.cc.common.component.JwtAuthComponent;
import com.esv.datacenter.cc.common.exception.RRException;
import com.esv.datacenter.cc.module.account.bo.TokenBO;
import com.esv.datacenter.cc.module.user.entity.UserEntity;
import com.esv.datacenter.cc.module.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.Map;
/**
* @description: 帐户中心服务实现类
* @author:hcbmailbox@163.com
* @date:2020/1/15
*/
@Service("accountService")
@Slf4j
@RefreshScope
public class AccountServiceImpl implements AccountService {
/**
* Token存活时间,单位:分钟
*/
@Value("${token.live.time.web:0}")
private Long tokenLiveTimeWeb;
private AccountPasswordComponent accountPasswordComponent;
private JwtAuthComponent jwtAuthComponent;
private UserService userService;
private UserLoginInfoService userLoginInfoService;
@Autowired
public AccountServiceImpl(AccountPasswordComponent accountPasswordComponent, JwtAuthComponent jwtAuthComponent,
UserService userService, UserLoginInfoService userLoginInfoService) {
this.accountPasswordComponent = accountPasswordComponent;
this.jwtAuthComponent = jwtAuthComponent;
this.userService = userService;
this.userLoginInfoService = userLoginInfoService;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String loginByAccountPwd(String account, String pwd, Map<String, Object> extMap) {
// 帐号密码校验
UserEntity userEntity = userService.getUserByAccount(account);
if (null == userEntity) {
throw new RRException("帐号不存在", 1001);
}
String salt = userEntity.getSalt();
String reqPwd = accountPasswordComponent.generatePasswordDB(pwd, salt);
if (!reqPwd.equals(userEntity.getPassword())) {
throw new RRException("密码错误", 1002);
}
// 创建Token
TokenBO tokenBO = new TokenBO();
tokenBO.setUserId(userEntity.getId());
tokenBO.setUserAccount(userEntity.getAccount());
tokenBO.setType(userEntity.getType());
tokenBO.setTenantId(userEntity.getTenantId());
tokenBO.setDepartmentId(userEntity.getDepartmentId());
tokenBO.setCreateTime(System.currentTimeMillis());
if (0L == tokenLiveTimeWeb) {
tokenBO.setExpireTime(0L);
} else {
// Token存活时间
Long expireTime = System.currentTimeMillis() + (tokenLiveTimeWeb * 60 * 60 * 1000);
tokenBO.setExpireTime(expireTime);
}
tokenBO.setIp(String.valueOf(extMap.get("ip")));
tokenBO.setSource("web");
// 将bean转换成map
BeanMap beanMap = BeanMap.create(tokenBO);
// 创建Token
String token = jwtAuthComponent.generateToken(beanMap);
log.info("帐号[{}]创建访问Token成功", account);
// 保存登录信息
UserLoginInfoEntity loginInfoEntity = new UserLoginInfoEntity();
loginInfoEntity.setUserId(userEntity.getId());
loginInfoEntity.setIp(String.valueOf(extMap.get("ip")));
loginInfoEntity.setToken(token);
loginInfoEntity.setStatus("0");
loginInfoEntity.setLoginTime(new Date());
loginInfoEntity.setLogoutTime(null);
userLoginInfoService.saveLoginInfo(loginInfoEntity);
return token;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void logout(TokenBO tokenBO) {
// 保存登出信息
UserLoginInfoEntity loginInfoEntity = new UserLoginInfoEntity();
loginInfoEntity.setUserId(tokenBO.getUserId());
loginInfoEntity.setStatus("1");
loginInfoEntity.setLogoutTime(new Date());
userLoginInfoService.saveLoginInfo(loginInfoEntity);
String account = tokenBO.getUserAccount();
log.info("帐号[{}]通过token登出成功", account);
}
}
package com.esv.datacenter.cc.module.account.service.impl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.esv.datacenter.cc.module.account.dao.UserLoginInfoDao;
import com.esv.datacenter.cc.common.exception.RRException;
import com.esv.datacenter.cc.module.account.dto.UserLoginInfoDTO;
import com.esv.datacenter.cc.module.account.entity.UserLoginInfoEntity;
import com.esv.datacenter.cc.module.account.service.UserLoginInfoService;
import com.esv.datacenter.cc.module.user.dto.UserDTO;
import com.esv.datacenter.cc.module.user.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service("userLoginInfoService")
public class UserLoginInfoServiceImpl extends ServiceImpl<UserLoginInfoDao, UserLoginInfoEntity> implements UserLoginInfoService {
private UserService userService;
@Autowired
public UserLoginInfoServiceImpl(UserService userService) {
this.userService = userService;
}
@Override
public UserLoginInfoDTO getUserLoginInfo(Long tenantId, Long userId) {
// 1.获取用户信息
Map<String, Object> queryObj = new HashMap<>();
queryObj.put("id", userId);
UserDTO userEntity = userService.getUserDetailInfo(queryObj);
if (null == userEntity) {
throw new RRException("未查询到当前帐号的信息", 500);
}
// 2.获取当前登录信息
UserLoginInfoEntity queryEntity = new UserLoginInfoEntity();
queryEntity.setUserId(userId);
Wrapper<UserLoginInfoEntity> queryWrapper = new QueryWrapper<>(queryEntity);
UserLoginInfoEntity loginInfoEntity = baseMapper.selectOne(queryWrapper);
if (null == loginInfoEntity) {
throw new RRException("未查询到当前帐号的登录信息", 500);
}
// 3.获取上一次登录信息
UserLoginInfoDTO userLoginInfoDTO = new UserLoginInfoDTO();
userLoginInfoDTO.setUserId(userEntity.getId());
userLoginInfoDTO.setAccount(userEntity.getAccount());
userLoginInfoDTO.setRealName(userEntity.getRealName());
userLoginInfoDTO.setEmail(userEntity.getEmail());
userLoginInfoDTO.setMobile(userEntity.getMobile());
userLoginInfoDTO.setDepartmentName(userEntity.getDepartmentName());
userLoginInfoDTO.setRoleName(userEntity.getRoleName());
userLoginInfoDTO.setStatus(loginInfoEntity.getStatus());
userLoginInfoDTO.setLoginIp(loginInfoEntity.getIp());
userLoginInfoDTO.setLoginTime(loginInfoEntity.getLoginTime().getTime());
if (null != loginInfoEntity.getLogoutTime()) {
userLoginInfoDTO.setLogoutTime(loginInfoEntity.getLogoutTime().getTime());
}
if (StringUtils.isNotBlank(loginInfoEntity.getLastIp())) {
userLoginInfoDTO.setLastLoginIp(loginInfoEntity.getLastIp());
}
if (null != loginInfoEntity.getLastLoginTime()) {
userLoginInfoDTO.setLastLoginTime(loginInfoEntity.getLastLoginTime().getTime());
}
return userLoginInfoDTO;
}
@Override
public int saveLoginInfo(UserLoginInfoEntity loginInfoEntity) {
UserLoginInfoEntity queryEntity = new UserLoginInfoEntity();
queryEntity.setUserId(loginInfoEntity.getUserId());
Wrapper<UserLoginInfoEntity> queryWrapper = new QueryWrapper<>(queryEntity);
UserLoginInfoEntity dbEntity = baseMapper.selectOne(queryWrapper);
if (null == dbEntity) {
return baseMapper.insert(loginInfoEntity);
} else {
loginInfoEntity.setId(dbEntity.getId());
// 修改时将登录信息保存为上次登录信息
loginInfoEntity.setLastIp(dbEntity.getIp());
loginInfoEntity.setLastLoginTime(dbEntity.getLoginTime());
return baseMapper.updateById(loginInfoEntity);
}
}
}
\ No newline at end of file
package com.esv.datacenter.cc.module.account.vo;
import lombok.Data;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.module.account.vo.LoginVO
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/17 10:26
* @version: 1.0
*/
@Data
public class LoginVO {
private String token;
}
package com.esv.datacenter.cc.module.apiauth.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.esv.datacenter.cc.common.form.Add;
import com.esv.datacenter.cc.common.form.Update;
import com.esv.datacenter.cc.module.apiauth.entity.ApiAuthorityEntity;
import com.esv.datacenter.cc.module.apiauth.form.ApiAuthorityDeleteForm;
import com.esv.datacenter.cc.module.apiauth.form.ApiAuthorityForm;
import com.esv.datacenter.cc.module.apiauth.service.ApiAuthorityService;
import com.esv.common.response.R;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @description: API鉴权数据维护Controller
* @author:hcbmailbox@163.com
* @date:2020/1/10
*/
@RestController
@RequestMapping("apiauth")
@Slf4j
public class ApiAuthController {
private ApiAuthorityService apiAuthorityService;
@Autowired
public ApiAuthController(ApiAuthorityService apiAuthorityService) {
this.apiAuthorityService = apiAuthorityService;
}
@GetMapping("/list")
public R list(
@RequestParam(value = "current", defaultValue = "1") Integer current,
@RequestParam(value = "size", defaultValue = "10") Integer size,
@RequestParam(value = "api", required = false) String api,
@RequestParam(value = "authType", required = false) String authType) {
IPage<ApiAuthorityEntity> page = new Page<>(current, size);
QueryWrapper<ApiAuthorityEntity> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(api)) {
wrapper.like("api", api);
}
if (StringUtils.isNotBlank(authType)) {
wrapper.eq("auth_type", authType);
}
page = apiAuthorityService.page(page, wrapper);
return R.ok(page);
}
@PostMapping("add")
public R add(@RequestBody @Validated(Add.class) ApiAuthorityForm apiAuthorityForm) {
ApiAuthorityEntity apiAuthorityEntity = new ApiAuthorityEntity();
BeanUtils.copyProperties(apiAuthorityForm, apiAuthorityEntity);
apiAuthorityService.save(apiAuthorityEntity);
apiAuthorityService.refreshApiMap();
return R.ok();
}
@PostMapping("update")
public R update(@RequestBody @Validated(Update.class) ApiAuthorityForm apiAuthorityForm) {
ApiAuthorityEntity apiAuthorityEntity = new ApiAuthorityEntity();
BeanUtils.copyProperties(apiAuthorityForm, apiAuthorityEntity);
apiAuthorityService.updateById(apiAuthorityEntity);
apiAuthorityService.refreshApiMap();
return R.ok();
}
@PostMapping("delete")
public R delete(@RequestBody @Validated ApiAuthorityDeleteForm apiAuthorityDeleteForm) {
List<Long> idList = apiAuthorityDeleteForm.getIdList();
apiAuthorityService.removeByIds(idList);
apiAuthorityService.refreshApiMap();
return R.ok();
}
/**
* 刷新Api Map
* @return
* @throws Exception
*/
@GetMapping("refresh")
public R refresh() {
apiAuthorityService.refreshApiMap();
return R.ok();
}
}
package com.esv.datacenter.cc.module.apiauth.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.esv.datacenter.cc.module.apiauth.entity.ApiAuthorityEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* API接口访问权限表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-21 10:45:29
*/
@Mapper
public interface ApiAuthorityDao extends BaseMapper<ApiAuthorityEntity> {
}
package com.esv.datacenter.cc.module.apiauth.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
/**
* API接口访问权限表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-21 10:45:29
*/
@Data
@TableName("cc_api_authority")
public class ApiAuthorityEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId
private Long id;
/**
* API接口URL
*/
private String api;
/**
* 权限类型:0-不鉴权、1-Token鉴权、2-授权鉴权
*/
private String authType;
/**
* 备注
*/
private String remark;
}
package com.esv.datacenter.cc.module.apiauth.form;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.module.apiauth.form.ApiAuthorityDeleteForm
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/17 15:58
* @version: 1.0
*/
@Data
public class ApiAuthorityDeleteForm {
@NotEmpty(message = "id不能为空")
private List<Long> idList;
}
package com.esv.datacenter.cc.module.apiauth.form;
import com.esv.datacenter.cc.common.form.Add;
import com.esv.datacenter.cc.common.form.Update;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* @description:
* @project: esv-cc
* @name: com.esv.cc.module.apiauth.form.ApiAuthorityForm
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/4/17 15:55
* @version: 1.0
*/
@Data
public class ApiAuthorityForm {
@NotNull(groups = Update.class, message = "id不能为空")
private Long id;
@NotNull(groups = {Add.class, Update.class}, message = "api不能为空")
private String api;
@NotNull(groups = {Add.class, Update.class}, message = "鉴权类型不能为空")
private String authType;
private String remark;
}
package com.esv.datacenter.cc.module.apiauth.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.esv.datacenter.cc.module.apiauth.entity.ApiAuthorityEntity;
import java.util.Map;
/**
* API接口访问权限表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-21 10:45:29
*/
public interface ApiAuthorityService extends IService<ApiAuthorityEntity> {
/**
* 获取所有API接口
* @return
*/
Map<String, Object> getAllApiMap();
/**
* 刷新Api Map
*/
void refreshApiMap();
}
package com.esv.datacenter.cc.module.apiauth.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.esv.datacenter.cc.module.apiauth.dao.ApiAuthorityDao;
import com.esv.datacenter.cc.module.apiauth.entity.ApiAuthorityEntity;
import com.esv.datacenter.cc.module.apiauth.service.ApiAuthorityService;
import com.esv.datacenter.cc.common.cache.CacheNames;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@CacheConfig(cacheNames = CacheNames.API_AUTHORITY)
@Service("apiAuthorityService")
public class ApiAuthorityServiceImpl extends ServiceImpl<ApiAuthorityDao, ApiAuthorityEntity> implements ApiAuthorityService {
// 缓存中该数据10分钟过期
@Cacheable(key = "'allApiMap'")
@Override
public Map<String, Object> getAllApiMap() {
Map<String, Object> map = new HashMap<>();
List<ApiAuthorityEntity> apiAuthorityEntityList = baseMapper.selectList(null);
apiAuthorityEntityList.forEach(apiAuthorityEntity ->
map.put(apiAuthorityEntity.getApi(), Integer.parseInt(apiAuthorityEntity.getAuthType()))
);
return map;
}
@CacheEvict(key = "'allApiMap'")
@Override
public void refreshApiMap() {
log.info("清除api缓存成功");
}
}
\ No newline at end of file
package com.esv.datacenter.cc.module.authentication.feign;
import com.esv.datacenter.cc.common.component.JwtAuthComponent;
import com.esv.datacenter.cc.common.constants.ApiResponseCode;
import com.esv.datacenter.cc.module.account.bo.TokenBO;
import com.esv.datacenter.cc.module.apiauth.service.ApiAuthorityService;
import com.esv.datacenter.cc.module.authentication.service.AuthenticationService;
import com.esv.datacenter.cc.util.RequestUriUtils;
import com.esv.common.response.ECode;
import com.esv.common.response.EResponse;
import com.esv.feign.cc.client.AuthFeignClient;
import com.esv.feign.cc.req.WebReqAuthReq;
import com.esv.feign.cc.res.WebReqAuthRes;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* @description:
* @project: cc
* @name: AuthFeignClientImpl
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/3/6 15:48
* @version:1.0
*/
@Slf4j
@RestController
public class AuthFeignClientImpl implements AuthFeignClient {
@Value("${auth.api.check.switch:true}")
private String apiCheckSwitch;
/**
* 文件下载url
**/
@Value("${auth.api.file-download-url:/file/download/direct}")
private String fileDownloadUrl;
private ApiAuthorityService apiAuthorityService;
private JwtAuthComponent jwtAuthComponent;
private AuthenticationService authenticationService;
@Autowired
public AuthFeignClientImpl(ApiAuthorityService apiAuthorityService, JwtAuthComponent jwtAuthComponent,
AuthenticationService authenticationService) {
this.apiAuthorityService = apiAuthorityService;
this.jwtAuthComponent = jwtAuthComponent;
this.authenticationService = authenticationService;
}
@Override
public EResponse<WebReqAuthRes> webReqAuth(String traceId, WebReqAuthReq webReqAuthReq) {
String reqUrl = webReqAuthReq.getReqUrl();
if (reqUrl.startsWith(fileDownloadUrl)) {
reqUrl = fileDownloadUrl;
}
String token = webReqAuthReq.getToken();
String menuCode = webReqAuthReq.getMenuCode();
log.info("系统鉴权开始 -- menuCode:{}, reqUrl:{}, token:{}", menuCode, reqUrl, token);
WebReqAuthRes webReqAuthRes = new WebReqAuthRes();
webReqAuthRes.setSystemCode(RequestUriUtils.getSystemCode(reqUrl));
webReqAuthRes.setDataPerm(0);
Map<String, Object> apiMap = apiAuthorityService.getAllApiMap();
if (!apiMap.containsKey(reqUrl)) {
// URL未注册
log.info("URL未注册:{}", reqUrl);
return EResponse.error(ApiResponseCode.URL_REGISTERED);
}
// 鉴权类型
int authType = (int) apiMap.get(reqUrl);
log.info("该接口鉴权类型authType:{}", authType);
// 接口不需鉴权
if (0 == authType) {
log.info("该请求不需要鉴权");
return EResponse.ok(webReqAuthRes).message("该请求不需要鉴权");
}
// 判断token格式是否正确
if (StringUtils.isEmpty(token)) {
log.info("无效的Token");
return EResponse.error(ECode.TOKEN_INVALID);
} else {
if (!token.startsWith("Basic ")) {
// token无效
log.info("Token格式错误");
return EResponse.error(ECode.TOKEN_INVALID);
}
token = StringUtils.trimToNull(token.replaceFirst("Basic ", ""));
}
// 解析token
TokenBO tokenBO = jwtAuthComponent.parseToken(token);
if (null == tokenBO) {
log.info("无效的Token");
return EResponse.error(ECode.TOKEN_INVALID);
} else if ((0L != tokenBO.getExpireTime())
&& (System.currentTimeMillis() > tokenBO.getExpireTime())) {
log.info("Token已过期");
return EResponse.error(ECode.TOKEN_EXPIRED);
}
// 拼装返回信息
webReqAuthRes.setUserId(tokenBO.getUserId());
webReqAuthRes.setAccount(tokenBO.getUserAccount());
webReqAuthRes.setTenantId(tokenBO.getTenantId());
webReqAuthRes.setDepartmentId(tokenBO.getDepartmentId());
// 接口只需token, 不需要具体权限
if (1 == authType) {
log.info("鉴权通过");
// 设置数据权限
authenticationService.setTokenDataPerm(tokenBO, webReqAuthRes);
return EResponse.ok(webReqAuthRes);
}
// 接口需要具体权限
if ("true".equals(apiCheckSwitch)) {
return authenticationService.access(webReqAuthRes, menuCode, reqUrl);
} else {
webReqAuthRes.setDataPerm(1);
return EResponse.ok(webReqAuthRes);
}
}
}
package com.esv.datacenter.cc.module.authentication.service;
import com.esv.datacenter.cc.module.account.bo.TokenBO;
import com.esv.common.response.EResponse;
import com.esv.feign.cc.res.WebReqAuthRes;
/**
* 权限验证服务,权限信息会进行缓缓,当相关内容变更时需要更新缓存
*/
public interface AuthenticationService {
/**
* description 开始鉴权
* param [webReqAuthRes, menuCode, url]
* return com.esv.common.response.EResponse<com.esv.feign.cc.res.WebReqAuthRes>
* author chenfm
* createTime 2020/4/4 13:57
**/
EResponse<WebReqAuthRes> access(WebReqAuthRes webReqAuthRes, String menuCode, String url);
/**
* description 设置Token校验时的数据权限
* param [tokenBO, webReqAuthRes]
* return void
* author HuangChaobin
* createTime 2020/06/17 11:30
**/
void setTokenDataPerm(TokenBO tokenBO, WebReqAuthRes webReqAuthRes);
/**
* 判断指定用户是否有权限访问url
* @param userId 用户名
* @param url url
* @return 有权限访问返回true,没有权限返回false
*/
boolean isAllowAccess(long userId, String url);
/**
* 用户删除、冻结时更新权限缓存
* @param userId 用户Id
*/
void updateCacheByUserId(long userId);
/**
* 角色信息删除、变更时更新权限缓存
* @param roleId
*/
void updateCacheByRoleId(long roleId);
/**
* 菜单信息变更、删除、锁定时更新权限缓存
* @param menuId
*/
void updateCacheByMenuId(long menuId);
}
package com.esv.datacenter.cc.module.authentication.service.impl;
import com.esv.datacenter.cc.common.constants.ApiResponseCode;
import com.esv.datacenter.cc.module.account.bo.TokenBO;
import com.esv.datacenter.cc.module.authentication.service.AuthenticationService;
import com.esv.datacenter.cc.module.department.service.DepartmentService;
import com.esv.datacenter.cc.module.menu.service.MenuService;
import com.esv.datacenter.cc.module.role.service.RoleMenuService;
import com.esv.datacenter.cc.module.system.entity.SystemEntity;
import com.esv.datacenter.cc.module.system.service.SystemService;
import com.esv.datacenter.cc.module.user.entity.UserEntity;
import com.esv.datacenter.cc.module.user.service.UserRoleService;
import com.esv.datacenter.cc.module.user.service.UserService;
import com.esv.datacenter.cc.util.RequestUriUtils;
import com.esv.common.response.EResponse;
import com.esv.feign.cc.res.WebReqAuthRes;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Service("authenticationService")
@Slf4j
public class AuthenticationServiceImpl implements AuthenticationService {
private SystemService systemService;
private UserService userService;
private UserRoleService userRoleService;
private RoleMenuService roleMenuService;
private MenuService menuService;
private DepartmentService departmentService;
@Autowired
public AuthenticationServiceImpl(SystemService systemService, UserService userService,
UserRoleService userRoleService, RoleMenuService roleMenuService,
MenuService menuService, DepartmentService departmentService) {
this.systemService = systemService;
this.userService = userService;
this.userRoleService = userRoleService;
this.roleMenuService = roleMenuService;
this.menuService = menuService;
this.departmentService = departmentService;
}
@Override
public EResponse<WebReqAuthRes> access(WebReqAuthRes webReqAuthRes, String menuCode, String url) {
Long userId = webReqAuthRes.getUserId();
log.info("用户鉴权开始 -- UserId:{}, MenuCode:{}, Url:{}", userId, menuCode, url);
if (userRoleService.hasSuperAdminRole(userId)) {
log.info("用户拥有超级管理员角色, 数据权限类型:{}", webReqAuthRes.getDataPerm());
return EResponse.ok(webReqAuthRes);
}
/** 取消根据应用进行鉴权 黄朝斌 2020/06/28 **/
// SystemEntity entity = systemService.getByCode(RequestUriUtils.getSystemCode(url));
// if (entity == null) {
// log.info("鉴权失败, 应用不存在");
// return EResponse.error(ApiResponseCode.SYSTEM_NOT_FOUND);
// }
/** 取消根据应用进行鉴权 黄朝斌 2020/06/28 **/
Set<String> userPermSet = menuService.userPermSet(null, userId, null);
String permStr = RequestUriUtils.getPermsUrl(url);
if (!userPermSet.contains(permStr)) {
log.info("鉴权失败, 用户没有该权限");
return EResponse.error(ApiResponseCode.NO_AUTHORITY);
}
Integer dataPerm = roleMenuService.findUserMenuCodeDataPerm(userId, menuCode);
// todo 前端请求中添加menuCode之后删除此段代码, 目前默认租户权限
if (dataPerm == null) {
dataPerm = 1;
}
// 如果是部门权限需要将下属部门全部列出
if (dataPerm == 2) {
// 部门id为0表示该组织就是租户, 与租户权限相同
if (webReqAuthRes.getDepartmentId() == 0L) {
dataPerm = 1;
}
List<Long> departmentIdList = new ArrayList<>();
departmentService.findCurrentAndChildrenId(departmentIdList, webReqAuthRes.getDepartmentId());
String departmentChildren = StringUtils.join(departmentIdList, ",");
webReqAuthRes.setDepartmentChildren(departmentChildren);
}
webReqAuthRes.setDataPerm(dataPerm);
log.info("鉴权成功, 数据权限类型:{}", dataPerm);
return EResponse.ok(webReqAuthRes);
}
@Override
public void setTokenDataPerm(TokenBO tokenBO, WebReqAuthRes webReqAuthRes) {
int type = tokenBO.getType();
if (0 == type) {
webReqAuthRes.setDataPerm(0);
} else if (1 == type) {
webReqAuthRes.setDataPerm(1);
} else {
// 部门id为0表示该组织就是租户, 与租户权限相同
if (webReqAuthRes.getDepartmentId() == 0L) {
webReqAuthRes.setDataPerm(1);
} else {
webReqAuthRes.setDataPerm(2);
List<Long> departmentIdList = new ArrayList<>();
departmentService.findCurrentAndChildrenId(departmentIdList, webReqAuthRes.getDepartmentId());
String departmentChildren = StringUtils.join(departmentIdList, ",");
webReqAuthRes.setDepartmentChildren(departmentChildren);
}
}
}
@Override
public boolean isAllowAccess(long userId, String url) {
log.info("鉴权开始 -- UserId:{}, Url:{}", userId, url);
Preconditions.checkArgument(StringUtils.isNotBlank(url));
if (userRoleService.hasSuperAdminRole(userId)) {
return true;
}
UserEntity userEntity = userService.getById(userId);
if (userEntity == null) {
log.warn("指定Id不存在,权限验证失败! userId: {}", userId);
return false;
}
if (userEntity.getStatus() == null || userEntity.getStatus() == 0) {
log.warn("指定用户已被锁定,权限验证失败! userId: {}", userId);
return false;
}
SystemEntity entity = systemService.getByCode(RequestUriUtils.getSystemCode(url));
if (entity == null) {
log.error("应用不存在");
return false;
}
Set<String> userPermSet = menuService.userPermSet(entity.getId(), userId, null);
String permStr = RequestUriUtils.getPermsUrl(url);
boolean result = userPermSet.contains(permStr);
log.info("鉴权结果 -- {}", result);
return result;
}
@Override
public void updateCacheByUserId(long userId) {
}
@Override
public void updateCacheByRoleId(long roleId) {
}
@Override
public void updateCacheByMenuId(long menuId) {
}
/**
* 通过userId来清空缓存
* @param userId 用户Id
*/
// @CacheEvict(value= CACHE_NAME_SPACE, key= CACHE_KEY)
public void clearCacheByUserId(long userId) {
// nothing
}
/**
* 通过userId检索该用户可以访问的Url
* @param userId 用户Id
* @return 权限Map,key -> url, value:menuId
*/
/*
@Cacheable(cacheNames = "userPerm", key = ("#root.args[0]" + "_" + "#root.args[1]"))
public Set<String> userPermSet(long systemId, long userId) {
List<String> permsList = menuService.listUserPerms(systemId, userId);
Set<String> permSet = new HashSet<>();
for (String perms : permsList) {
if (StringUtils.isNotBlank(perms)) {
permSet.addAll(Arrays.asList(perms.split(";")));
}
}
return permSet;
}
*/
/**
* 过滤掉字符串前后的 '/'
*/
public String filterUrl(String url) {
int len = url.length();
int st = 0;
char[] val = url.toCharArray();
while ((st < len) && (val[st] == '/')) {
st++;
}
while ((st < len) && (val[len - 1] == '/')) {
len--;
}
return ((st > 0) || (len < url.length())) ? url.substring(st, len) : url;
}
}
package com.esv.datacenter.cc.module.cache.controller;
import com.esv.datacenter.cc.module.cache.service.CacheTestService;
import com.esv.datacenter.cc.module.user.entity.UserEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("cache")
@CacheConfig(cacheNames = {"user"})
public class CacheTestController {
private CacheTestService cacheTestService;
@Autowired
public CacheTestController(CacheTestService cacheTestService) {
this.cacheTestService = cacheTestService;
}
/**
* 查询出一条数据并且添加到缓存
*
* @param userId
* @return
*/
@RequestMapping(value = "/getUser", method = RequestMethod.GET)
@Cacheable
public UserEntity getPrud(@RequestParam(required = true) String userId) {
log.info("如果没有缓存,就会调用下面方法,如果有缓存,则直接输出,不会输出此段话");
return cacheTestService.getUser(Integer.parseInt(userId));
}
@PostMapping("getUser1")
@Cacheable(key = "#userEntity.id")
public UserEntity getPrud1(@RequestBody UserEntity userEntity) {
log.info("如果没有缓存,就会调用下面方法,如果有缓存,则直接输出,不会输出此段话");
return cacheTestService.getUser(userEntity.getId().intValue());
}
/**
* 删除一个缓存
*
* @param userId
* @return
*/
@RequestMapping(value = "/deleteUser", method = RequestMethod.GET)
// @CacheEvict("userCache")
@CacheEvict
public String deleteUser(@RequestParam(required = true) String userId) {
return "删除成功";
}
@PostMapping("deleteUser1")
@CacheEvict
public String deleteUser1(@RequestBody UserEntity userEntity) {
return "删除成功";
}
/**
* 添加一条保存的数据到缓存,缓存的key是当前user的id
*
* @param user
* @return
*/
@RequestMapping(value = "/saveUser", method = RequestMethod.POST)
// @CachePut(value = "userCache", key = "#result.userId +''")
@CachePut(key = "#result.userId +''")
public UserEntity saveUser(UserEntity user) {
return user;
}
/**
* 返回结果userPassword中含有nocache字符串就不缓存
*
* @param userId
* @return
*/
@RequestMapping(value = "/getUser2", method = RequestMethod.GET)
@CachePut(value = "userCache", unless = "#result.userPassword.contains('nocache')")
public UserEntity getUser2(@RequestParam(required = true) String userId) {
log.info("如果走到这里说明,说明缓存没有生效!");
UserEntity user = new UserEntity();
user.setId(Long.valueOf(userId));
user.setAccount("name_nocache"+userId);
user.setPassword("password_" + userId);
return user;
}
@RequestMapping(value = "/getUser3", method = RequestMethod.GET)
@Cacheable(value = "userCache", key = "#root.targetClass.getName() + #root.methodName + #userId")
public UserEntity getUser3(@RequestParam(required = true) String userId) {
log.info("如果第二次没有走到这里说明缓存被添加了");
return cacheTestService.getUser(Integer.parseInt(userId));
}
}
package com.esv.datacenter.cc.module.cache.service;
import com.esv.datacenter.cc.module.user.entity.UserEntity;
import org.springframework.stereotype.Service;
@Service("CacheTestService")
public class CacheTestService {
public UserEntity getUser(int userId) {
System.out.println("执行此方法,说明没有缓存,如果没有走到这里,就说明缓存成功了");
UserEntity user = new UserEntity();
user.setId(Long.valueOf(userId));
user.setAccount("没有缓存_"+userId);
user.setPassword("password_" + userId);
return user;
}
public UserEntity getUser2(int userId) {
System.out.println("执行此方法,说明没有缓存,如果没有走到这里,就说明缓存成功了");
UserEntity user = new UserEntity();
user.setId(Long.valueOf(userId));
user.setAccount("没有缓存_"+userId);
user.setPassword("password_" + userId);
return user;
}
}
package com.esv.datacenter.cc.module.department.controller;
import com.esv.datacenter.cc.common.form.Add;
import com.esv.datacenter.cc.common.form.Update;
import com.esv.datacenter.cc.module.department.entity.DepartmentEntity;
import com.esv.datacenter.cc.module.department.form.DepartmentDeleteForm;
import com.esv.datacenter.cc.module.department.form.DepartmentForm;
import com.esv.datacenter.cc.module.department.service.DepartmentService;
import com.esv.datacenter.cc.module.department.vo.DepartmentChooseVO;
import com.esv.datacenter.cc.module.department.vo.DepartmentInfoVO;
import com.esv.datacenter.cc.module.department.vo.DepartmentVO;
import com.esv.datacenter.cc.module.tenant.service.TenantService;
import com.esv.common.exception.EException;
import com.esv.common.response.R;
import com.esv.gateway.common.GatewayHeaders;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* 部门表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-09 11:32:08
*/
@Slf4j
@RestController
@RequestMapping("department")
public class DepartmentController {
private DepartmentService departmentService;
private TenantService tenantService;
@Autowired
public DepartmentController(DepartmentService departmentService, TenantService tenantService) {
this.departmentService = departmentService;
this.tenantService = tenantService;
}
/**
* description 查询租户部门树列表
* param [tenantId, departmentName]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/17 13:37
**/
@GetMapping("listTree")
public R listTree(
@RequestHeader(GatewayHeaders.DATA_PERM) Integer dataPerm,
@RequestHeader(GatewayHeaders.TENANT_ID) Long tenantId,
@RequestHeader(GatewayHeaders.DEPARTMENT_ID) Long departmentId,
@RequestParam(value = "departmentName", required = false) String departmentName
) {
// 以租户信息为要结点查询部门信息
List<DepartmentVO> departmentVOList;
if ((dataPerm == 2) && (departmentId != 0)) {
// departmentId = 0表示该部门是租户级
departmentVOList = new ArrayList<>(1);
DepartmentEntity departmentEntity = departmentService.getById(departmentId);
DepartmentVO departmentVO = new DepartmentVO(departmentEntity);
departmentVO.setChildren(departmentService.listDepartmentTree(tenantId, departmentId, departmentName));
departmentVOList.add(departmentVO);
} else {
departmentVOList = tenantService.TenantDepartmentVOTreeList(dataPerm, tenantId, departmentName);
}
return R.ok(departmentVOList);
}
/**
* description 查询部门详细信息
* param [departmentId]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/17 13:39
**/
@GetMapping("info")
public R info(@RequestParam("departmentId") String departmentId) {
DepartmentInfoVO departmentInfoVO;
if (departmentId.startsWith("t_")) {
// 如果查询部门id以t_开头说明为租户
Long tenantId = Long.parseLong(departmentId.split("_")[1]);
departmentInfoVO = tenantService.tenantInfo(tenantId);
} else {
// 查询部门信息
departmentInfoVO = departmentService.departmentInfo(Long.parseLong(departmentId));
}
if (departmentInfoVO == null) {
return R.error("没有数据");
}
return R.ok(departmentInfoVO);
}
/**
* description 新增部门信息
* param [userId, departmentForm]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/17 13:40
**/
@PostMapping("add")
public R add(@RequestBody @Validated(Add.class) DepartmentForm departmentForm) {
DepartmentEntity departmentEntity = new DepartmentEntity();
long parentId;
long tenantId;
if (departmentForm.getParentId().startsWith("t_")) {
// 加入租户的根部门
parentId = 0;
tenantId = Long.parseLong(departmentForm.getParentId().split("_")[1]);
} else {
// 加入子部门
parentId = Long.parseLong(departmentForm.getParentId());
DepartmentEntity entity = departmentService.getById(parentId);
if (parentId != 0 && entity == null) {
return R.error("该上级组织不存在");
}
tenantId = entity.getTenantId();
}
BeanUtils.copyProperties(departmentForm, departmentEntity);
departmentEntity.setParentId(parentId);
departmentEntity.setTenantId(tenantId);
if (departmentService.save(departmentEntity)) {
return R.ok();
} else {
return R.error();
}
}
/**
* description 修改时可选择部门列表
* param [departmentId]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/17 13:40
**/
@GetMapping("chooseList")
public R chooseList(
@RequestHeader(GatewayHeaders.DATA_PERM) Integer dataPerm,
@RequestHeader(GatewayHeaders.TENANT_ID) Long tenantId,
@RequestHeader(GatewayHeaders.DEPARTMENT_ID) Long departmentId,
@RequestParam("departmentId") String chooseDepartmentId) {
List<DepartmentVO> departmentVOList;
if ((dataPerm == 2) && (departmentId != 0)) {
// departmentId = 0表示该部门是租户级
departmentVOList = new ArrayList<>(1);
DepartmentEntity departmentEntity = departmentService.getById(departmentId);
DepartmentVO departmentVO = new DepartmentVO(departmentEntity);
departmentVO.setChildren(departmentService.listDepartmentTree(tenantId, departmentId, null));
departmentVOList.add(departmentVO);
} else {
Integer queryDataPerm = dataPerm;
Long queryTenantId = tenantId;
// 查询要修改部门的租户
if (StringUtils.isNotBlank(chooseDepartmentId)) {
queryDataPerm = null;
DepartmentEntity entity = departmentService.getById(chooseDepartmentId);
queryTenantId = entity.getTenantId();
}
departmentVOList = tenantService.TenantDepartmentVOTreeList(queryDataPerm, queryTenantId, null);
}
List<DepartmentChooseVO> list = new ArrayList<>(departmentVOList.size());
for (DepartmentVO departmentVO : departmentVOList) {
list.add(departmentService.makeChooseVO(chooseDepartmentId, departmentVO));
}
return R.ok(list);
}
/**
* description 修改部门信息
* param [userId, departmentUpdateForm]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/17 13:40
**/
@PostMapping("update")
public R update(@RequestBody @Validated(Update.class) DepartmentForm departmentForm) {
long id = departmentForm.getId();
DepartmentEntity departmentEntity = departmentService.getById(id);
long tenantId = departmentEntity.getTenantId();
long parentId;
if (departmentForm.getParentId().startsWith("t_")) {
// 修改为租户根部门
parentId = 0;
} else {
// 修改为子部门
parentId = Long.parseLong(departmentForm.getParentId());
if (departmentService.getById(parentId) == null) {
return R.error("该上级组织不存在");
}
// 检查上级部门是否为当前及下级部门
List<DepartmentVO> departmentVOList =
departmentService.listDepartmentTree(tenantId, id, null);
if ((id == parentId) || treeHasId(departmentVOList, parentId)) {
return R.error("该上级组织不可更改为当前及下级组织");
}
}
BeanUtils.copyProperties(departmentForm, departmentEntity);
departmentEntity.setParentId(parentId);
if (departmentService.updateById(departmentEntity)) {
return R.ok();
} else {
return R.error();
}
}
/**
* description 树列表是否包括指定id
* param [departmentVOList, parentId]
* return boolean
* author chenfm
* createTime 2020/3/17 13:41
**/
private boolean treeHasId(List<DepartmentVO> departmentVOList, long parentId) {
for (DepartmentVO departmentVO : departmentVOList) {
if (Long.parseLong(departmentVO.getId()) == parentId) {
return true;
}
if (departmentVO.getChildren() != null) {
if(treeHasId(departmentVO.getChildren(), parentId)) {
return true;
}
}
}
return false;
}
/**
* description 删除部门
* param [userId, departmentDeleteForm]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/17 13:41
**/
@PostMapping("delete")
public R delete(@RequestBody @Validated DepartmentDeleteForm departmentDeleteForm) {
if (departmentDeleteForm.getDepartmentId().startsWith("t_")) {
return R.error("根部门不可删除");
}
try {
departmentService.deleteById(Long.parseLong(departmentDeleteForm.getDepartmentId()));
} catch (EException e) {
return R.error(e.getMsg());
}
return R.ok();
}
}
package com.esv.datacenter.cc.module.department.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.esv.datacenter.cc.module.department.dto.DepartmentDTO;
import com.esv.datacenter.cc.module.department.entity.DepartmentEntity;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 部门表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-09 11:32:08
*/
@Mapper
public interface DepartmentDao extends BaseMapper<DepartmentEntity> {
/**
* description 根据上级id查询部门列表
* param [tenantId, parentId, departmentName]
* return java.util.List<com.esv.cc.module.department.dto.DepartmentDTO>
* author chenfm
* createTime 2020/4/1 11:27
**/
List<DepartmentDTO> selectByParentId(long tenantId, Long parentId, String departmentName);
}
package com.esv.datacenter.cc.module.department.dto;
import com.esv.datacenter.cc.module.department.entity.DepartmentEntity;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.List;
/**
* 包含子部门的实体
* @author chenfm
*/
@Data
@JsonInclude
public class DepartmentDTO extends DepartmentEntity {
private Integer userCount;
private List<DepartmentDTO> children;
}
package com.esv.datacenter.cc.module.department.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 部门表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-09 11:32:08
*/
@Data
@TableName("cc_department")
public class DepartmentEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 部门id
*/
@TableId
private Long id;
/**
* 部门名
*/
private String departmentName;
/**
* 上级部门id
*/
private Long parentId;
/**
* 租户id
*/
private Long tenantId;
/**
* 分类:1.集团/2.分公司/3.部门
*/
private String category;
/**
* 负责人
*/
private String principal;
/**
* 电话
*/
private String phone;
/**
* 备注
*/
private String remark;
/**
* 排序
*/
private Integer orderNum;
/**
* 创建用户
*/
@TableField(fill = FieldFill.INSERT)
private String createUser;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 更新用户
*/
@TableField(fill = FieldFill.UPDATE)
private String updateUser;
/**
* 更新时间
*/
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
/**
* 已删除
*/
@TableLogic
private Boolean deleted;
}
package com.esv.datacenter.cc.module.department.form;
import lombok.Data;
import javax.validation.constraints.NotNull;
/**
* @author chenfm
*/
@Data
public class DepartmentDeleteForm {
@NotNull(message = "部门id不能为空")
private String departmentId;
}
package com.esv.datacenter.cc.module.department.form;
import com.esv.datacenter.cc.common.form.Delete;
import com.esv.datacenter.cc.common.form.Update;
import com.esv.datacenter.cc.common.form.Add;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
/**
* @author chenfm
*/
@Data
public class DepartmentForm {
@NotNull(groups = {Update.class, Delete.class}, message = "部门id不能为空")
private Long id;
/**
* 部门名
*/
@NotNull(groups = {Add.class, Update.class}, message = "部门名不能为空")
@Length(groups = {Add.class, Update.class}, max = 50, message = "部门名长度不合法")
private String departmentName;
/**
* 上级部门id
*/
@NotNull(groups = {Add.class, Update.class}, message = "请选择上级部门")
private String parentId;
/**
* 分类:1.集团/2.分公司/3.部门
*/
private String category;
/**
* 负责人
*/
@Length(groups = {Add.class, Update.class}, max = 50, message = "负责人长度不合法")
private String principal;
/**
* 电话
*/
@Length(groups = {Add.class, Update.class}, max = 50, message = "电话长度不合法")
private String phone;
/**
* 备注
*/
@Length(groups = {Add.class, Update.class}, max = 500, message = "备注长度不合法")
private String remark;
/**
* 排序
*/
@NotNull(groups = {Add.class, Update.class}, message = "显示排序值不能为空")
private int orderNum;
}
package com.esv.datacenter.cc.module.department.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.esv.datacenter.cc.module.department.entity.DepartmentEntity;
import com.esv.datacenter.cc.module.department.vo.DepartmentChooseVO;
import com.esv.datacenter.cc.module.department.vo.DepartmentInfoVO;
import com.esv.datacenter.cc.module.department.vo.DepartmentVO;
import java.util.List;
/**
* @description:
* @project: cc
* @name: DepartmentService
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/3/4 15:01
* @version:1.0
*/
public interface DepartmentService extends IService<DepartmentEntity> {
/**
* description 查询所有部门树列表
* param [parentId, departmentName]
* return java.util.List<DepartmentDTO>
* author chenfm
* createTime 2020/3/10 9:13
**/
List<DepartmentVO> listDepartmentTree(long tenantId, long parentId, String departmentName);
/**
* description 查询部门详细信息
* param [departmentId]
* return DepartmentInfoVO
* author chenfm
* createTime 2020/3/17 13:52
**/
DepartmentInfoVO departmentInfo(Long departmentId);
/**
* description 查询上级部门名称列表
* param [departmentId]
* return java.util.List<java.lang.String>
* author chenfm
* createTime 2020/3/10 9:15
**/
List<String> getParentNameList(long departmentId);
/**
* description 删除部门及下属所有部门
* param [departmentId]
* return void
* author chenfm
* createTime 2020/3/10 9:15
**/
void deleteById(long departmentId);
/**
* description 查询可修改上级组织
* param [departmentId, parentId]
* return java.util.List<DepartmentChooseVO>
* author chenfm
* createTime 2020/3/10 9:15
**/
List<DepartmentChooseVO> chooseList(Long tenantId, Long parentId, String departmentId);
/**
* description 处理可选部门
* param [departmentId, departmentVO]
* return com.esv.cc.module.department.vo.DepartmentChooseVO
* author chenfm
* createTime 2020/4/4 16:15
**/
DepartmentChooseVO makeChooseVO(String departmentId, DepartmentVO departmentVO);
/**
* description 查询当前及所有下属组织id
* param [departmentIdList, departmentId]
* return void
* author chenfm
* createTime 2020/4/4 16:18
**/
void findCurrentAndChildrenId(List<Long> departmentIdList, Long departmentId);
}
package com.esv.datacenter.cc.module.department.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.esv.datacenter.cc.module.department.dao.DepartmentDao;
import com.esv.datacenter.cc.module.department.dto.DepartmentDTO;
import com.esv.datacenter.cc.module.department.entity.DepartmentEntity;
import com.esv.datacenter.cc.module.department.service.DepartmentService;
import com.esv.datacenter.cc.module.department.vo.DepartmentChooseVO;
import com.esv.datacenter.cc.module.department.vo.DepartmentInfoVO;
import com.esv.datacenter.cc.module.department.vo.DepartmentVO;
import com.esv.datacenter.cc.module.user.dao.UserDao;
import com.esv.datacenter.cc.module.user.entity.UserEntity;
import com.esv.common.exception.EException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.List;
/**
* @author chenfm
*/
@Service("departmentService")
public class DepartmentServiceImpl extends ServiceImpl<DepartmentDao, DepartmentEntity> implements DepartmentService {
private UserDao userDao;
@Autowired
public DepartmentServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
/**
* description 递归查询部门树列表
* param [tenantId, parentId, departmentName]
* return java.util.List<DepartmentDTO>
* author chenfm
* createTime 2020/3/11 13:55
**/
@Override
public List<DepartmentVO> listDepartmentTree(long tenantId, long parentId, String departmentName) {
List<DepartmentDTO> list = baseMapper.selectByParentId(tenantId, parentId, departmentName);
List<DepartmentVO> departmentVOList = new ArrayList<>(list.size());
for (DepartmentDTO dto : list) {
DepartmentVO departmentVO = new DepartmentVO();
BeanUtils.copyProperties(dto, departmentVO);
departmentVO.setId(String.valueOf(dto.getId()));
departmentVO.setParentId(String.valueOf(dto.getParentId()));
int userCount = dto.getUserCount();
List<DepartmentVO> children = listDepartmentTree(tenantId, dto.getId(), departmentName);
for (DepartmentVO child : children) {
userCount += child.getUserCount();
}
departmentVO.setChildren(children);
departmentVO.setUserCount(userCount);
departmentVOList.add(departmentVO);
}
return departmentVOList;
}
@Override
public DepartmentInfoVO departmentInfo(Long departmentId) {
DepartmentEntity departmentEntity = getById(departmentId);
if (departmentEntity == null) {
return null;
}
DepartmentInfoVO departmentInfoVO = new DepartmentInfoVO();
BeanUtils.copyProperties(departmentEntity, departmentInfoVO);
departmentInfoVO.setId(String.valueOf(departmentEntity.getId()));
if (departmentEntity.getParentId() == 0) {
departmentInfoVO.setParentId("t_" + departmentEntity.getTenantId());
} else {
departmentInfoVO.setParentId(String.valueOf(departmentEntity.getParentId()));
}
List<String> parentNameList = getParentNameList(departmentEntity.getParentId());
if (!parentNameList.isEmpty()) {
departmentInfoVO.setParentName(parentNameList.get(parentNameList.size() - 1));
departmentInfoVO.setParentNameList(parentNameList);
}
return departmentInfoVO;
}
@Override
public List<String> getParentNameList(long departmentId) {
List<String> list = new ArrayList<>();
if (departmentId == 0) {
return list;
}
DepartmentEntity entity = baseMapper.selectById(departmentId);
list.addAll(getParentNameList(entity.getParentId()));
list.add(entity.getDepartmentName());
return list;
}
@Transactional
@Override
public void deleteById(long departmentId) {
DepartmentEntity entity = new DepartmentEntity();
entity.setParentId(departmentId);
List<DepartmentEntity> list = list(new QueryWrapper<>(entity));
for (DepartmentEntity departmentEntity : list) {
deleteById(departmentEntity.getId());
}
// 判断要删除的部门中是否有用户
UserEntity userEntity = new UserEntity();
userEntity.setDepartmentId(departmentId);
int userCount = userDao.selectCount(new QueryWrapper<>(userEntity));
if (userCount != 0) {
throw new EException("该部门或下级部门存在用户");
}
removeById(departmentId);
}
@Override
public List<DepartmentChooseVO> chooseList(Long tenantId, Long parentId, String departmentId) {
List<DepartmentVO> list = this.listDepartmentTree(tenantId, parentId, null);
List<DepartmentChooseVO> chooseVOList = new ArrayList<>();
for (DepartmentVO departmentVO : list) {
DepartmentChooseVO departmentChooseVO = makeChooseVO(departmentId, departmentVO);
if (departmentChooseVO != null) {
chooseVOList.add(departmentChooseVO);
}
}
return chooseVOList;
}
public DepartmentChooseVO makeChooseVO(String departmentId, DepartmentVO departmentVO) {
if (StringUtils.isNotBlank(departmentId) && departmentVO.getId().equals(departmentId)) {
return null;
}
DepartmentChooseVO departmentChooseVO = new DepartmentChooseVO();
departmentChooseVO.setId(departmentVO.getId());
departmentChooseVO.setDepartmentName(departmentVO.getDepartmentName());
if (departmentVO.getChildren() != null) {
List<DepartmentChooseVO> chooseVOList = new ArrayList<>();
for (DepartmentVO child : departmentVO.getChildren()) {
DepartmentChooseVO childVO = makeChooseVO(departmentId, child);
if (childVO != null) {
chooseVOList.add(childVO);
}
}
if (!chooseVOList.isEmpty()) {
departmentChooseVO.setChildren(chooseVOList);
}
}
return departmentChooseVO;
}
@Override
public void findCurrentAndChildrenId(List<Long> departmentIdList, Long departmentId) {
departmentIdList.add(departmentId);
DepartmentEntity departmentEntity = new DepartmentDTO();
departmentEntity.setParentId(departmentId);
QueryWrapper<DepartmentEntity> wrapper = new QueryWrapper<>(departmentEntity);
List<DepartmentEntity> list = baseMapper.selectList(wrapper);
for (DepartmentEntity entity : list) {
findCurrentAndChildrenId(departmentIdList, entity.getId());
}
}
}
package com.esv.datacenter.cc.module.department.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.List;
/**
* @author chenfm
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class DepartmentChooseVO {
/**
* 部门id
*/
private String id;
/**
* 部门名
*/
private String departmentName;
/**
* 子部门列表
*/
private List<DepartmentChooseVO> children;
}
package com.esv.datacenter.cc.module.department.vo;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.List;
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class DepartmentInfoVO {
/**
* 部门id
*/
private String id;
/**
* 部门名
*/
private String departmentName;
/**
* 上级部门id
*/
private String parentId;
/**
* 租户id
*/
private Long tenantId;
/**
* 分类:1.集团/2.分公司/3.部门
*/
private String category;
/**
* 负责人
*/
private String principal;
/**
* 电话
*/
private String phone;
/**
* 备注
*/
private String remark;
/**
* 排序
*/
private int orderNum;
/**
* 上级部门名称
*/
private String parentName;
/**
* 所有上级名称列表
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<String> parentNameList;
}
package com.esv.datacenter.cc.module.department.vo;
import com.esv.datacenter.cc.module.department.entity.DepartmentEntity;
import com.esv.datacenter.cc.module.tenant.entity.TenantEntity;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.List;
/**
* @description:
* @project: esv-cc
* @name: DepartmentVO
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/3/11 13:31
* @version:1.0
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DepartmentVO {
/**
* 部门id
*/
private String id;
/**
* 部门名
*/
private String departmentName;
/**
* 上级部门id
*/
private String parentId;
/**
* 租户id
*/
private Long tenantId;
/**
* 分类:1.集团/2.分公司/3.部门
*/
private String category;
/**
* 负责人
*/
private String principal;
/**
* 电话
*/
private String phone;
/**
* 备注
*/
private String remark;
/**
* 排序
*/
private int orderNum;
/**
* @description 用户数
* @author chenfm
* @createTime 2020/3/11 13:32
**/
private Integer userCount;
/**
* @description 子部门
* @author chenfm
* @createTime 2020/3/11 13:32
**/
private List<DepartmentVO> children;
public DepartmentVO() {
}
public DepartmentVO(TenantEntity tenantEntity) {
this.id = "t_" + tenantEntity.getId();
this.departmentName = tenantEntity.getTenantName();
this.parentId = "0";
this.tenantId = tenantEntity.getId();
this.category = "0";
this.principal = tenantEntity.getContact();
this.phone = tenantEntity.getContactPhone();
this.userCount = 0;
}
public DepartmentVO(DepartmentEntity departmentEntity) {
this.id = String.valueOf(departmentEntity.getId());
this.departmentName = departmentEntity.getDepartmentName();
this.parentId = String.valueOf(departmentEntity.getParentId());
this.tenantId = departmentEntity.getTenantId();
this.category = "2";
this.principal = departmentEntity.getPrincipal();
this.phone = departmentEntity.getPhone();
}
}
package com.esv.datacenter.cc.module.index.controller;
import com.esv.datacenter.cc.module.index.service.IndexService;
import com.esv.datacenter.cc.module.index.vo.IndexSystemVO;
import com.esv.datacenter.cc.module.menu.dto.MenuDTO;
import com.esv.datacenter.cc.module.system.entity.SystemEntity;
import com.esv.datacenter.cc.module.system.service.SystemService;
import com.esv.common.response.R;
import com.esv.gateway.common.GatewayHeaders;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Slf4j
@RestController
@RequestMapping("index")
public class IndexController {
private IndexService indexService;
private SystemService systemService;
@Autowired
public IndexController(IndexService indexService, SystemService systemService) {
this.indexService = indexService;
this.systemService = systemService;
}
/**
* description 查询所有系统菜单
* param [userId]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/13 17:27
**/
@Transactional
@GetMapping("userMenuTree")
public R userMenuTree(@RequestHeader(GatewayHeaders.USER_ID) Long userId) {
List<SystemEntity> systemList = systemService.list();
List<IndexSystemVO> systemVOList = new ArrayList<>(systemList.size());
for (SystemEntity entity : systemList) {
IndexSystemVO indexSystemVO = new IndexSystemVO();
BeanUtils.copyProperties(entity, indexSystemVO);
List<MenuDTO> menuDTOList = indexService.userSystemMenuTree(userId, entity.getId());
indexSystemVO.setMenuList(menuDTOList);
systemVOList.add(indexSystemVO);
}
return R.ok(systemVOList);
}
/**
* description 查询所有系统按钮权限
* param [userId]
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/13 17:27
**/
@Transactional
@GetMapping("userMenuCodeList")
public R userMenuCodeList(@RequestHeader(GatewayHeaders.USER_ID) Long userId) {
Set<String> menuCodeSet = new HashSet<>();
List<SystemEntity> systemList = systemService.list();
for (SystemEntity entity : systemList) {
List<String> menuCodeList = indexService.menuCodeList(userId, entity.getId());
for (String menuCode : menuCodeList) {
if (StringUtils.isNotBlank(menuCode)) {
menuCodeSet.add(menuCode);
}
}
}
return R.ok(menuCodeSet);
}
/*
@Transactional
@RequestMapping("userPermsList")
public R userPermsList(@RequestHeader(HttpHeaderKeys.USER_ID) Long userId,
@RequestHeader(HttpHeaderKeys.SYSTEM_CODE) String systemCode) {
SystemEntity entity = systemService.selectByUri(systemCode);
if (entity == null) {
return R.error("应用不存在");
}
List<String> permsList = menuService.listUserPerms(entity.getId(),
userId == Long.parseLong(superAdminUserId) ? null : userId);
Set<String> permsSet = new HashSet<>();
for (String perms : permsList) {
if (StringUtils.isNotBlank(perms)) {
permsSet.add(perms);
}
}
return R.ok(permsSet);
}
*/
}
package com.esv.datacenter.cc.module.index.service;
import com.esv.datacenter.cc.module.menu.dto.MenuDTO;
import java.util.List;
/**
* @description:
* @project: cc
* @name: com.esvtek.ymjt.cc.module.index.service.IndexService
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/3/5 16:51
* @version:1.0
*/
public interface IndexService {
/**
* description 查询所有系统菜单
* param [userId, systemId]
* return java.util.List<MenuDTO>
* author chenfm
* createTime 2020/3/13 17:57
**/
List<MenuDTO> userSystemMenuTree(Long userId, Long systemId);
/**
* description 查询所有系统按钮权限
* param [userId, systemId]
* return java.util.List<java.lang.String>
* author chenfm
* createTime 2020/3/13 17:57
**/
List<String> menuCodeList(Long userId, Long systemId);
}
package com.esv.datacenter.cc.module.index.service.impl;
import com.esv.datacenter.cc.module.index.service.IndexService;
import com.esv.datacenter.cc.module.menu.dto.MenuDTO;
import com.esv.datacenter.cc.module.menu.service.MenuService;
import com.esv.datacenter.cc.module.user.service.UserRoleService;
import com.esv.datacenter.cc.module.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @description:
* @project: cc
* @name: IndexServiceImpl
* @author: chenfm
* @email: chenfengman@esvtek.com
* @createTime: 2020/3/5 17:11
* @version:1.0
*/
@Service("indexServiceImpl")
public class IndexServiceImpl implements IndexService {
private UserRoleService userRoleService;
private UserService userService;
private MenuService menuService;
@Autowired
public IndexServiceImpl(UserRoleService userRoleService, UserService userService,
MenuService menuService) {
this.userRoleService = userRoleService;
this.userService = userService;
this.menuService = menuService;
}
@Override
public List<MenuDTO> userSystemMenuTree(Long userId, Long systemId) {
List<MenuDTO> menuDTOList;
if (userRoleService.hasSuperAdminRole(userId)) {
// 超级管理员查询所有菜单
menuDTOList = menuService.listSystemMenu(systemId, null, null);
} else {
// 其他按角色权限查询
menuDTOList = menuService.listSystemMenu(systemId, userId, null);
}
return menuDTOList;
}
@Override
public List<String> menuCodeList(Long userId, Long systemId) {
List<String> menuCodeList;
if (userRoleService.hasSuperAdminRole(userId)) {
// 超级管理员查询所有菜单
menuCodeList = menuService.listMenuCode(systemId, null, null);
} else {
// 其他按角色权限查询
menuCodeList = menuService.listMenuCode(systemId, userId, null);
}
return menuCodeList;
}
}
package com.esv.datacenter.cc.module.index.vo;
import com.esv.datacenter.cc.module.system.vo.SystemVO;
import com.esv.datacenter.cc.module.menu.dto.MenuDTO;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.util.List;
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class IndexSystemVO extends SystemVO {
List<MenuDTO> menuList;
}
package com.esv.datacenter.cc.module.menu.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.esv.datacenter.cc.common.form.Add;
import com.esv.datacenter.cc.common.form.Update;
import com.esv.datacenter.cc.form.IdForm;
import com.esv.datacenter.cc.module.menu.dto.SystemMenuDTO;
import com.esv.datacenter.cc.module.menu.entity.MenuEntity;
import com.esv.datacenter.cc.module.menu.form.MenuForm;
import com.esv.datacenter.cc.module.menu.service.MenuService;
import com.esv.common.response.R;
import com.esv.gateway.common.GatewayHeaders;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 菜单管理
*/
@Slf4j
@RestController
@RequestMapping("menu")
public class MenuController {
private MenuService menuService;
@Autowired
public MenuController(MenuService menuService) {
this.menuService = menuService;
}
/**
* description 菜单树列表
* param []
* return com.esv.common.response.R
* author chenfm
* createTime 2020/3/12 9:28
**/
@GetMapping("listTree")
public R listTree(@RequestHeader(GatewayHeaders.USER_ID) Long userId) {
List<SystemMenuDTO> systemMenuDTOList = menuService.listSystemMenuTree(userId);
return R.ok(systemMenuDTOList);
}
@Transactional
@PostMapping("add")
public R add(@RequestBody @Validated(Add.class) MenuForm menuForm) {
String menuCode = menuForm.getMenuCode();
QueryWrapper<MenuEntity> wrapper = new QueryWrapper<>();
wrapper.eq("menu_code", menuCode);
if (!menuService.list(wrapper).isEmpty()) {
return R.error("该菜单编码已存在");
}
menuService.saveOrUpdate(menuForm);
return R.ok();
}
@PostMapping("update")
public R update(@RequestBody @Validated(Update.class) MenuForm menuForm) {
String menuCode = menuForm.getMenuCode();
if (StringUtils.isNotBlank(menuCode)) {
QueryWrapper<MenuEntity> wrapper = new QueryWrapper<>();
wrapper.ne("id", menuForm.getId());
wrapper.eq("menu_code", menuCode);
if (menuService.count(wrapper) != 0) {
return R.error("该菜单编码已存在");
}
}
menuService.saveOrUpdate(menuForm);
return R.ok();
}
@PostMapping("delete")
public R delete(@RequestBody @Validated IdForm idForm) {
Long id = idForm.getId();
menuService.removeMenuTree(id);
return R.ok();
}
}
package com.esv.datacenter.cc.module.menu.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.esv.datacenter.cc.module.menu.entity.MenuEntity;
import com.esv.datacenter.cc.module.menu.dto.MenuDTO;
import com.esv.datacenter.cc.module.menu.dto.SystemMenuDTO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 菜单管理
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-10 15:25:41
*/
@Mapper
public interface MenuDao extends BaseMapper<MenuEntity> {
/**
* description 根据用户和租户权限查询可用系统及目录
* param [tenantId, userId]
* return java.util.List<SystemMenuDTO>
* author chenfm
* createTime 2020/3/12 10:41
**/
List<SystemMenuDTO> listSystemMenuTree(Long userId);
/**
* description 查询子菜单
* param [parentId]
* return java.util.List<MenuDTO>
* author chenfm
* createTime 2020/3/12 10:41
**/
List<MenuDTO> queryByParentId(@Param("parentId") long parentId, Long userId);
/**
* description 根据系统查询菜单
* param [param]
* return java.util.List<MenuDTO>
* author chenfm
* createTime 2020/3/12 10:42
**/
List<MenuDTO> querySystemMenu(Map<String, Object> param);
/**
* description 查询系统根菜单
* param [param]
* return java.util.List<com.esv.cc.module.menu.dto.MenuDTO>
* author chenfm
* createTime 2020/6/24 10:40
**/
List<MenuDTO> systemTypeMenu(Map<String, Object> param);
/**
* description 查询用户权限
* param [param]
* return java.util.List<java.lang.String>
* author chenfm
* createTime 2020/3/12 10:42
**/
List<String> queryPermsByUser(Map<String, Object> param);
List<String> queryMenuCodeByUser(Map<String, Object> param);
}
package com.esv.datacenter.cc.module.menu.dto;
import lombok.Data;
import java.util.List;
@Data
public class MenuDTO {
/**
* 菜单id
*/
private Long id;
/**
* 父菜单ID,一级菜单为0
*/
private Long parentId;
/**
* 菜单编码
*/
private String menuCode;
/**
* 上级名称
*/
private String parentName;
/**
* 菜单名称
*/
private String name;
/**
* 菜单URL
*/
private String url;
/**
* 授权(多个用逗号分隔,如:user:list,user:create)
*/
private String perms;
/**
* 类型 1:目录 2:菜单 3:按钮
*/
private Integer type;
/**
* 菜单图标
*/
private String icon;
/**
* 排序
*/
private Integer orderNum;
/**
* 状态 0:正常/1:锁定
*/
private Integer status;
/**
* 系统id
*/
private Long systemId;
/**
* 菜单列表
*/
private List<MenuDTO> children;
/**
* 字段唯一标识
**/
private String rowKey;
/**
* description 数据权限
* author chenfm
* createTime 2020/4/9 10:36
**/
private Integer dataPerm;
/**
* description 用户数据权限
* author chenfm
* createTime 2020/4/10 10:26
**/
private Integer userDataPerm;
/**
* 上级字段唯一标识
**/
private String parentRowKey;
private Boolean available;
public String getRowKey() {
return id + "_" + type;
}
}
package com.esv.datacenter.cc.module.menu.dto;
import lombok.Data;
import java.util.List;
@Data
public class SystemMenuDTO {
/**
* 系统id
*/
private Long id;
/**
* 系统名称
*/
private String name;
/**
* 系统图标
*/
private String icon;
/**
* 系统url
*/
private String url;
/**
* 状态 0:正常/1:锁定
*/
private Integer status;
/**
* 类型 -1:应用 0:目录 1:菜单 2:按钮
*/
private Integer type = -1;
/**
* 字段唯一标识
**/
private String rowKey;
/**
* 菜单列表
*/
private List<MenuDTO> children;
public String getRowKey() {
return id + "_" + type;
}
}
package com.esv.datacenter.cc.module.role.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.esv.datacenter.cc.module.role.entity.RoleCategoryEntity;
import com.esv.datacenter.cc.module.role.dto.RoleCategoryDTO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 角色类别表
*
* @author chenfm
* @email chenfengman@esvtek.com
* @date 2020-01-10 15:25:41
*/
@Mapper
public interface RoleCategoryDao extends BaseMapper<RoleCategoryEntity> {
List<RoleCategoryDTO> queryAllCategoryWithRole(Long tenantId);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment