Commit 28791d16 by tongpuxin

云教投放落地页配置后台、小程序短链接配置后台

parent 88745193
...@@ -34,14 +34,6 @@ ...@@ -34,14 +34,6 @@
</properties> </properties>
<dependencies> <dependencies>
<!-- 引用公共模块 -->
<dependency>
<groupId>cn.gladiolus</groupId>
<artifactId>gladiolus-core</artifactId>
<version>3.0.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
......
package com.app.framework.core.api.constant;
/**
* API接口常量类
*/
public class ApiConstant {
/**
* 请求头信息 - 身份认证数据
*/
public static final String HEADER_AUTHORIZATION = "Authorization";
/**
* 请求头信息 - 平台
*/
public static final String HEADER_PLATFORM = "Platform";
/**
* 身份认证失败
*/
public static final String ID_AUTH_FAILURE = "401";
}
package com.app.framework.core.api.filter;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.ContentType;
import com.alibaba.fastjson.JSON;
import com.app.framework.core.api.constant.ApiConstant;
import com.app.framework.core.api.request.ApiHttpServletRequest;
import com.app.framework.core.api.request.ApiLoginUser;
import com.app.framework.core.api.service.ApiService;
import com.app.framework.core.api.utils.ApiExcludeRegisterCenter;
import com.app.framework.core.support.view.form.AjaxResult;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* API接口身份认证拦截器
* 所有资源都是受保护的,需要排除的资源通过ApiExcludeRegisterCenter注册。
* 根据请求头中的Authorization信息,验证用户身份,并将用户ID(apiLoginUserId参数)放入request
*/
public class ApiHttpServletRequestFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(ApiHttpServletRequestFilter.class);
private String loginUri = "/login";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String loginUri = filterConfig.getInitParameter("loginUri");
if (StringUtils.isNotBlank(loginUri)) {
this.loginUri = loginUri;
}
String excludedUri = filterConfig.getInitParameter("excludedUri");
if (StringUtils.isNotBlank(excludedUri)) {
String[] excludedUris = excludedUri.split(",");
ApiExcludeRegisterCenter.register(excludedUris);
}
}
@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) srequest;
HttpServletResponse response = (HttpServletResponse) sresponse;
//跨域嗅探(跨域请求时会在真正的请求之前发送一次options请求,用于嗅探.此时是不携带请求头信息的,且不能做其他处理)
if (request.getMethod().equals("OPTIONS")) {
chain.doFilter(srequest, sresponse);
}
//正式请求
else {
//获取请求的uri
String uri = request.getRequestURI();
//获取Authorization(初次登录时没有Authorization)
String Authorization = request.getHeader(ApiConstant.HEADER_AUTHORIZATION);
//获取Platform
String Platform = request.getHeader(ApiConstant.HEADER_PLATFORM);
// if(logger.isInfoEnabled()) {
// logger.info(String.format("身份认证[URI = %s][Authorization = %s][Platform = %s]:", uri, Authorization, Platform));
// }
//认证
if (StringUtils.isNotBlank(loginUri) && uri.indexOf(loginUri) > -1) {//登录,不验证Authorization
chain.doFilter(srequest, sresponse);
} else if (ApiExcludeRegisterCenter.isExcluded(uri)) {//被排除的uri,无需认证身份,但获取apiLoginUser值
if (StringUtils.isNotBlank(Authorization)) {
AjaxResult<ApiLoginUser> result = this.IDAuth(Authorization, Platform);
if (result.success()) {
ApiLoginUser apiLoginUser = result.getData();
request.setAttribute("apiLoginUser", apiLoginUser);
chain.doFilter(new ApiHttpServletRequest(request, apiLoginUser.getId()), sresponse);
} else {
chain.doFilter(srequest, sresponse);
}
} else {
chain.doFilter(srequest, sresponse);
}
} else {//其他请求,需验证Authorization
//身份认证
AjaxResult<ApiLoginUser> result = this.IDAuth(Authorization, Platform);
if (result.success()) {
ApiLoginUser apiLoginUser = result.getData();
request.setAttribute("apiLoginUser", apiLoginUser);
chain.doFilter(new ApiHttpServletRequest(request, apiLoginUser.getId()), sresponse);
} else {
ServletUtil.write(response, JSON.toJSONString(result), ContentType.JSON.toString(StandardCharsets.UTF_8));
}
}
}
}
@Override
public void destroy() {
}
/**
* 身份认证
*
* @param Authorization
* @param Platform
*/
private AjaxResult<ApiLoginUser> IDAuth(String Authorization, String Platform) {
AjaxResult<ApiLoginUser> result = AjaxResult.wrap(false);
if (StringUtils.isNotBlank(Authorization)) {
ApiService apiService = SpringUtil.getBean(ApiService.class);
result = apiService.checkToken(Platform, Authorization);
if (!result.success()) {
result.setCode(ApiConstant.ID_AUTH_FAILURE);
result.setMsg("身份认证失败");
}
} else {
result.setCode(ApiConstant.ID_AUTH_FAILURE);
result.setMsg("请在请求头中传入Authorization参数");
}
return result;
}
}
package com.app.framework.core.api.paging;
/**
* Api分页
*/
public class ApiPaging {
/**当前页码*/
private Integer page = 1;
/**每页显示记录数*/
private Integer limit = 10;
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
}
package com.app.framework.core.api.paging;
import com.app.framework.core.support.view.grid.Paging;
import java.util.List;
/**
* Api分页返回数据
* @param <T>
*/
public class ApiPagingData<T> {
/**
* 分页信息
*/
private PagingResult paging;
/**
* 分页数据
*/
private List<T> data;
public PagingResult getPaging() {
return paging;
}
public void setPaging(PagingResult paging) {
this.paging = paging;
}
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
public ApiPagingData(Paging paging, List<T> data){
PagingResult pagingResult = new PagingResult();
if(paging != null) {
pagingResult.setPageNo(paging.getPageNo());
pagingResult.setLimit(paging.getLimit());
pagingResult.setTotalCount(paging.getTotalCount());
pagingResult.setTotalPage(paging.getTotalPage());
}
this.setPaging(pagingResult);
this.setData(data);
}
public class PagingResult {
/**当前页码*/
private Integer pageNo;
/**每页显示记录数*/
private Integer limit;
/**总记录*/
private Long totalCount;
/**总页数*/
private Long totalPage;
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public Long getTotalCount() {
if(totalCount == null){
totalCount = 0L;
}
return totalCount;
}
public void setTotalCount(Long totalCount) {
this.totalCount = totalCount;
}
public Long getTotalPage() {
if(totalPage == null){
totalPage = 0L;
}
return totalPage;
}
public void setTotalPage(Long totalPage) {
this.totalPage = totalPage;
}
}
}
package com.app.framework.core.api.request;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* Api的HttpServletRequest,主要是完成如下功能:
* 因API要求不直接传递用户信息,而是传递一个token用于身份认证。故通过重写request参数将认证后的用户信息传入请求的方法中,认证失败则直接返回401代码的错误
*
*/
@SuppressWarnings({"unchecked"})
public class ApiHttpServletRequest extends HttpServletRequestWrapper {
private static final String MEMBER_ID = "apiLoginUserId";
private Long apiLoginUserId = null;
public ApiHttpServletRequest(HttpServletRequest request) {
super(request);
}
public ApiHttpServletRequest(HttpServletRequest request, Long apiLoginUserId) {
super(request);
this.apiLoginUserId = apiLoginUserId;
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value == null && MEMBER_ID.equals(name) && apiLoginUserId != null) {
value = apiLoginUserId.toString();
}
return value;
}
@Override
public Map getParameterMap() {
Map map = super.getParameterMap();
if (!map.containsKey(MEMBER_ID) && apiLoginUserId != null) {
map = new HashMap(map);
map.put(MEMBER_ID, apiLoginUserId.toString());
}
return map;
}
@Override
public Enumeration getParameterNames() {
if (super.getParameter(MEMBER_ID) == null && apiLoginUserId != null) {
return Collections.enumeration(getParameterMap().keySet());
} else {
return super.getParameterNames();
}
}
@Override
public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
if (values == null && MEMBER_ID.equals(name) && apiLoginUserId != null) {
values = new String[]{apiLoginUserId.toString()};
}
return values;
}
}
\ No newline at end of file
package com.app.framework.core.api.request;
import com.app.framework.core.support.auth.LoginUser;
import lombok.Data;
import java.io.Serializable;
/**
* Api登录用户
*/
@Data
public class ApiLoginUser implements LoginUser, Serializable {
/**
* 用户ID
*/
private Long id;
/**
* 用户姓名
*/
private String realName;
/**
* 用户登录名
*/
private String username;
/**
* 用户类型(1:普通注册用户)
*/
private Integer userType;
/**
* 所属机构ID
*/
private Long organizationId;
public static ApiLoginUser userId(Long userId) {
ApiLoginUser loginUser = new ApiLoginUser();
loginUser.setId(userId);
return loginUser;
}
}
package com.app.framework.core.api.service;
import cn.hutool.core.date.DateUtil;
import com.app.framework.core.api.request.ApiLoginUser;
import com.app.framework.core.support.enums.common.PlatformEnum;
import com.app.framework.core.support.view.form.AjaxResult;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Date;
import java.util.Map;
/**
* Api接口
* 校验验令牌
*/
public interface ApiService {
/**
* 根据平台生成token
*
* @param platform 平台类型{@link PlatformEnum}
* @param expires token有效时间(单位小时,0或null则永久有效)
* @param loginUser 登录用户信息
* @return token
*/
default String createToken(String platform, Integer expires, ApiLoginUser loginUser) {
JWTCreator.Builder builder = JWT.create();
builder.withClaim("platform", platform);
builder.withClaim("userId", loginUser.getId());
if (expires != null && expires > 0)
builder.withExpiresAt(DateUtil.offsetHour(new Date(), expires));//设置过期时间
return builder.sign(Algorithm.HMAC256("ApiUserToken"));//设置签名 密钥
}
/**
* 校验token并返回登录用户信息
*
* @param platform 平台类型{@link PlatformEnum}
* @param token 用户token
*/
default AjaxResult<ApiLoginUser> checkToken(String platform, String token) {
try {
//创建验证对象,这里使用的加密算法和密钥必须与生成TOKEN时的相同否则无法验证
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("ApiUserToken")).build();
//验证JWT
DecodedJWT decodedJWT = jwtVerifier.verify(token);
Map<String, Claim> claims = decodedJWT.getClaims();
Long userId = claims.get("userId").asLong();
return AjaxResult.wrapData(ApiLoginUser.userId(userId));
} catch (Exception e) {
return AjaxResult.wrapError("身份验证失败");
}
}
/**
* 移除用户信息
*
* @param platform 平台类型{@link PlatformEnum}
* @param loginUser 登录用户信息
*/
default AjaxResult removeToken(String platform, ApiLoginUser loginUser) {
return AjaxResult.wrap(false);
}
}
package com.app.framework.core.api.utils;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* API接口要排除的uri注册中心
* 通过ApiExcludeRegisterCenter.register(String uri)方法注册
* 在此注册过的uri不会被拦截器拦截
*
*/
public class ApiExcludeRegisterCenter {
/**
* 要排除的uri集合
*/
private static Set<String> excludeList = new HashSet<>();
/**
* 注册要排除的uri
* @param uri 要排除的uri
*/
public static void register(String uri){
excludeList.add(uri);
}
/**
* 批量注册要排除的uri
* @param array 要排除的uri数组
*/
public static void register(String[] array){
if(array != null && array.length > 0){
excludeList.addAll(Arrays.asList(array));
}
}
/**
* 判断请求的URL是否被排除拦截
* @param url 请求的URL
* @return 是否排除
*/
public static boolean isExcluded(String url) {
if(!excludeList.isEmpty()){
for (String u : excludeList){
if(url.indexOf(u) > -1)
return true;
}
}
return false;
}
}
package com.app.framework.core.api.utils;
import com.app.framework.core.api.request.ApiLoginUser;
import javax.servlet.http.HttpServletRequest;
/**
* Api登录用户工具类
*/
public class ApiLoginUserUtils {
/**
* 获取Api登录用户
* @param request
* @return
*/
public static ApiLoginUser getLoginUser(HttpServletRequest request) {
return (ApiLoginUser) request.getAttribute("apiLoginUser");
}
}
package com.app.framework.core.exception;
/**
* 自定义异常类
* 用于验证失败抛出异常,该异常会通过AjaxResult对象输出至前端
* 此异常不会在控制台抛出(因为在异常控制中心ExceptionCenterController捕获了)
* eg.
* 1)参数必填、格式验证失败
* 2)Service中判断失败需事物回滚
*
*/
public class ValidException extends RuntimeException {
private static final long serialVersionUID = 1700233072924690954L;
public ValidException(String message, Throwable cause) {
super(message, cause);
}
public ValidException(String message) {
super(message);
}
public ValidException(Throwable cause) {
super(cause);
}
}
package com.app.framework.core.exception;
import org.apache.commons.lang.exception.ExceptionUtils;
/**
* 验证异常工具类
*/
public class ValidUtils {
/**
* 抛出异常,expression为true时抛出,否则什么都不做
* @param expression 是否抛出异常
* @param msg 异常消息
*/
public static void valid (boolean expression, String msg) {
if (expression)
throw new ValidException(msg);
}
/**
* 抛出异常,expression为true时抛出,否则什么都不做
* @param expression 是否抛出异常
*/
public static void validBlank (boolean expression) {
if (expression) {
throw new ValidException("必需项不能为空");
}
}
public static boolean isValidException(Throwable e) {
return ExceptionUtils.indexOfThrowable(e, ValidException.class) != -1;
}
}
package com.app.framework.core.exception.global.appender;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
/**
* 全局异常输出器
* 可自定义输出至DB或MongoDB
*/
public interface ExceptionAppenderBase {
void append(HttpServletRequest request, HandlerMethod handlerMethod, Exception e, long timeStamp);
}
package com.app.framework.core.exception.global.controller;
import cn.hutool.extra.spring.SpringUtil;
import com.app.framework.core.exception.ValidException;
import com.app.framework.core.exception.global.appender.ExceptionAppenderBase;
import com.app.framework.core.support.view.form.AjaxResult;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
/**
* 异常中心控制器
* 此处可将异常入库备查
*/
@ControllerAdvice
public class ExceptionCenterController {
private static final Logger logger = LoggerFactory.getLogger(ExceptionCenterController.class.getName());
private static String argEx[] = {"ClientAbortException"};
@ExceptionHandler(value = ValidException.class)
@ResponseBody
public AjaxResult exceptionHandler(HttpServletRequest request, ValidException ex){
return AjaxResult.wrapError(ex.getMessage());
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public AjaxResult exceptionHandler(HttpServletRequest request, HandlerMethod handlerMethod, Exception ex){
/*
* 处理忽略异常
*/
if (isIgnoreException(ex)) {
return null;
}
//异常记录
ExceptionAppenderBase appender = SpringUtil.getBean(ExceptionAppenderBase.class);
if(appender != null){
appender.append(request, handlerMethod, ex, System.currentTimeMillis());
}
//异常输出至控制台
ex.printStackTrace();
String error = this.processException(ex);
return AjaxResult.wrapError(error);
}
private boolean isIgnoreException(Exception e) {
for (String name : argEx) {
if (name.equals(e.getClass().getSimpleName())) {
return true;
}
}
return false;
}
private String processException(Throwable exception) {
String resultError = "";
if (exception instanceof DataIntegrityViolationException) {
String errorMsg = exception.getMessage();
if (errorMsg.indexOf("ORA-02291") >= 0) {
errorMsg = ExceptionMsgConst.MSG_INSERT_FAILED_NOPARENT; // 外键引用的表中无此记录(通常情况下可能不会出现此异常,因为前台页面上应该是从下拉列表框中选择而非手工输入数据)
} else if (errorMsg.indexOf("ORA-02292") >= 0) {
errorMsg = ExceptionMsgConst.MSG_DELETE_FAILED_REFERENCED;// 作为别的表中的外键且数据被引用
} else if (errorMsg.indexOf("ORA-00001") >= 0) {
errorMsg = ExceptionMsgConst.MSG_INSERT_FAILED_NOTUNIQUE; // 数据不唯一
} else {
errorMsg = ExceptionMsgConst.MSG_FAILED_OTHER;
}
// log.error("数据违反唯一约束条件", exception);
resultError = errorMsg;
} else if (exception instanceof DataAccessException) {
// log.error("数据访问异常", exception);
resultError = ExceptionMsgConst.MSG_FAILED_OTHER;
} else if (exception instanceof ConstraintViolationException) {
// log.error("业务方法执行异常:", exception);
resultError = ExceptionMsgConst.MSG_DELETE_FAILED_REFERENCED;
} else if (exception instanceof IllegalArgumentException) {
// log.error("业务方法执行异常:", exception);
resultError = ExceptionMsgConst.MSG_ILLEGAL_ARGUMENT;
}
if(StringUtils.isBlank(resultError))resultError = "未知异常";
return resultError;
}
protected final class ExceptionMsgConst {
public static final String MSG_DELETE_FAILED_REFERENCED = "删除失败,该条记录被引用";
public static final String MSG_INSERT_FAILED_NOPARENT = "添加失败,引用记录不存在";
public static final String MSG_INSERT_FAILED_NOTUNIQUE = "添加失败,相同记录已存在";
public static final String MSG_FAILED_OTHER = "数据存取失败,请检查数据正确性";
public static final String MSG_ILLEGAL_ARGUMENT = "参数不合法";
}
}
package com.app.framework.core.log.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 方法执行结束之后切入
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface LogOps {
/**
* 操作类型
* 可自定义
*/
String type();
/**
* 操作内容
*/
String description() default "";
}
package com.app.framework.core.log.constant;
/**
* 日志操作类型
*/
public class LogOpsType {
/**
* 登录
*/
public final static String LOGIN = "LOGIN";
/**
* 注销
*/
public final static String LOGOUT = "LOGOUT";
/**
* 移动端登录
*/
public final static String MLOGIN = "MLOGIN";
/**
* 添加
*/
public final static String ADD = "ADD";
/**
* 更新
*/
public final static String UPDATE = "UPDATE";
/**
* 删除
*/
public final static String DELETE = "DELETE";
/**
* 同步
*/
public final static String PUSH = "PUSH";
}
package com.app.framework.core.log.intercept;
import java.util.HashMap;
import java.util.Map;
/**
* 日志记录器注册中心
* 用来关联拦截的class 与 具体的日志记录器
*/
public class LogInterceptCenter {
private static Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>();
public static Class<?> getHandler(Class<?> c) {
return map.get(c);
}
/**
* 注册日志拦截器
* @param c 要拦截日志的class
* @param interceptClass 拦截器class
*/
public static void register(Class<?> c, Class<?> interceptClass){
map.put(c, interceptClass);
}
}
package com.app.framework.core.log.intercept;
import cn.hutool.core.util.TypeUtil;
/**
* 日志拦截器基类
* [子类注意:拦截器中定义的方法必须与Controller中对应的方法同名同参]
*
* @param <Controller> 需要拦截的Controller
*/
public class LogInterceptSupport<Controller> {
public LogInterceptSupport(){
Class<?> controllerClass = (Class)TypeUtil.getTypeArgument(getClass());
LogInterceptCenter.register(controllerClass, getClass());
}
}
package com.app.framework.core.log.result;
/**
* 日志列对象
* 操作的列信息
*/
public class LogColumn {
private String columnKey;
private String columnName;
private Object columnValue;
public LogColumn(String columnKey, String columnName, Object columnValue) {
super();
this.columnKey = columnKey;
this.columnName = columnName;
this.columnValue = columnValue;
}
public String getColumnKey() {
return columnKey;
}
public void setColumnKey(String columnKey) {
this.columnKey = columnKey;
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public Object getColumnValue() {
return columnValue;
}
public void setColumnValue(Object columnValue) {
this.columnValue = columnValue;
}
public boolean isColumnValueEmpty() {
if (columnValue == null || columnValue.toString().equals(""))
return true;
return false;
}
}
package com.app.framework.core.log.result;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* 日志结果对象
* 操作类型和操作的列
*/
public class LogResult {
/** 操作人ID */
private Long operatorId;
/** 操作人姓名 */
private String operatorName;
/** 操作类型 */
private String operType;
/** 操作字段集合 */
private List<LogColumn> logColumns = new ArrayList<LogColumn>();
public LogResult() {}
public LogResult(String operType) {
this.operType = operType;
}
public Long getOperatorId() {
return operatorId;
}
public void setOperatorId(Long operatorId) {
this.operatorId = operatorId;
}
public String getOperatorName() {
return operatorName;
}
public void setOperatorName(String operatorName) {
this.operatorName = operatorName;
}
public String getOperType() {
return operType;
}
public void setOperType(String operType) {
this.operType = operType;
}
public LogResult addColumn(String key, String column, Object v) {
logColumns.add(new LogColumn(key, column, v));
return this;
}
public LogResult addColumn(LogColumn column) {
logColumns.add(column);
return this;
}
public List<LogColumn> getLogColumns() {
return logColumns;
}
public void setLogColumns(List<LogColumn> logColumns) {
this.logColumns = logColumns;
}
/**
* 处理 columnList
* @return
*/
public String processLogColmnList() {
StringBuilder str = new StringBuilder();
for (int i = 0, size = logColumns.size(); i < size; i++) {
LogColumn column = logColumns.get(i);
if(StringUtils.isNotBlank(column.getColumnName())){
str.append(column.getColumnName());
str.append(":");
}
if(!column.isColumnValueEmpty()) {
str.append(column.getColumnValue());
}
if (i < size - 1)
str.append(",");
}
return str.toString();
}
}
package com.app.framework.core.log.task;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.app.framework.core.log.intercept.LogInterceptCenter;
import com.app.framework.core.log.result.LogResult;
import org.aspectj.lang.JoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
public class LogResultTask {
Logger logger = LoggerFactory.getLogger(LogResultTask.class.getName());
public LogResult logResult(JoinPoint jp){
LogResult logResult = null;
//获取拦截方法信息
String targetMethodName = jp.getSignature().getName(); // 拦截方法名
Class<?> targetClass = jp.getTarget().getClass(); // 拦截class
Object[] args = jp.getArgs(); // 拦截参数
// 匹配interceptClass
Class<?> interceptClass = LogInterceptCenter.getHandler(targetClass);
if (interceptClass == null) {
logger.warn(String.format("don't find interceptClass, targetClass:[%s]", targetClass));
return logResult;
}
// 从容器中获取拦截器实例
Object interceptObject = SpringUtil.getBean(interceptClass);
if (interceptObject == null){
logger.warn("interceptObject is null");
return logResult;
}
// 利用反射从拦截器中取得对应的日志处理函数
Method findMethod = ReflectUtil.getMethod(interceptClass, targetMethodName, ClassUtil.getClasses(args));
if (findMethod == null) {
// logger.warn(String.format("class : [%s], paramTypes : [%s] find method : [%s] failure", interceptClass, Arrays.toString(paramsTypes), targetMethodName));
logger.warn(String.format("class : [%s] find method : [%s] failure", interceptClass, targetMethodName));
return logResult;
}
// 处理具体日志方法
Object resultObject = null;
try {
// 具体日志处理方法
resultObject = findMethod.invoke(interceptObject, args);
} catch (Exception e) {
logger.error(String.format("[%s] invoke method : [%s] failure", interceptClass, targetMethodName), e);
}
// 处理和解析对象输出日志
if (resultObject != null) {
logResult = (LogResult) resultObject;
}
return logResult;
}
}
package com.app.framework.core.support.auth;
/**
* 登录用户接口 存入session的登录用户对象必须实现该接口
*/
public interface LoginUser {
/**
* 默认密码
*/
public final static String DEFAULT_PWD = "e10adc3949ba59abbe56e057f20f883e";
/**
* 机构(平台方)
*/
public final static Long ORGANIZATION_SUPER = 0L;
/**
* 用户类型(超级管理员)
*/
public final static Integer TYPE_SUPER = 0;
/**
* 用户类型(机构管理员,机构创建时同步创建)
*/
public final static Integer TYPE_ADMIN = 1;
/**
* 用户类型(普通管理员即员工)
*/
public final static Integer TYPE_EMP = 2;
/**
* 获取登录账号Id
*
* @return Long
*/
Long getId();
/**
* 获取登录用户姓名
*
* @return String
*/
String getRealName();
/**
* 获取登录名
*
* @return String
*/
String getUsername();
/**
* 获取用户类型
*/
Integer getUserType();
/**
* 获取所属机构ID
*/
Long getOrganizationId();
}
\ No newline at end of file
package com.app.framework.core.support.controller;
import com.app.framework.core.log.annotation.LogOps;
import com.app.framework.core.log.constant.LogOpsType;
import com.app.framework.core.support.view.form.AjaxResult;
import com.app.framework.core.support.view.grid.ExGridLoad;
import com.app.framework.core.support.view.grid.Paging;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* Controller基类,所有Controller都必须继承该类
* 提供获取请求头信息的各种方法
* 提供获取参数的各种方法
* 提供基础的增删改查请求
*/
public abstract class CrudBaseControllerSupport<E> extends CrudControllerSupport {
/**
* 查询列表的具体实现
* @param request HttpServletRequest
* @param view 查询条件
* @param paging 分页条件
* @return 查询结果
*/
public abstract <V> List<V> list(HttpServletRequest request, final E view, Paging paging);
/**
* 保存记录的具体实现
* @param request HttpServletRequest
* @param entity 实体对象
*/
public abstract AjaxResult saveEntity(HttpServletRequest request, E entity);
/**
* 批量删除记录,根据Id
* @param request HttpServletRequest
* @param oids 主键Id数组
*/
public abstract AjaxResult batchDelete(HttpServletRequest request, Long oids[]);
/**
* 查询所有记录,支持分页
*/
@RequestMapping(value = "/list")
public @ResponseBody ExGridLoad listByPaging(HttpServletRequest request, E view, Paging paging) {
List<E> views = this.list(request, view, paging);
return ExGridLoad.wrapExGridLoad(views, paging);
}
/**
* 保存记录
*/
@RequestMapping(value = "/saveEntity")
@LogOps(type = LogOpsType.UPDATE)
public @ResponseBody AjaxResult saveByEntity(HttpServletRequest request, E entity){
return this.saveEntity(request, entity);
}
/**
* 删除记录,根据Id
*/
@RequestMapping(value = "/deleteById")
@LogOps(type = LogOpsType.DELETE)
public @ResponseBody AjaxResult deleteById(HttpServletRequest request, Long oid) {
Assert.notNull(oid, "id不能为空.");
return this.batchDelete(request, new Long[]{oid});
}
/**
* 批量删除记录,根据Id
*/
@RequestMapping(value = "/batchDelete")
@LogOps(type = LogOpsType.DELETE)
public @ResponseBody AjaxResult deleteByBatch(HttpServletRequest request, Long oids[]) {
Assert.notNull(oids, "ids不能为空.");
return this.batchDelete(request, oids);
}
}
package com.app.framework.core.support.controller;
import com.app.framework.core.support.filter.DateConvertEditor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import java.util.Date;
/**
* Controller基类,所有Controller都必须继承该类
* 提供获取请求头信息的各种方法
* 提供获取参数的各种方法
*/
public abstract class CrudControllerSupport {
protected Logger logger = null;
public CrudControllerSupport(){
logger = LoggerFactory.getLogger(getClass().getName());
}
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Date.class, null, new DateConvertEditor());
binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
}
}
package com.app.framework.core.support.convert;
import cn.hutool.core.util.TypeUtil;
import com.app.framework.core.support.view.tree.ExTreeNode;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
/**
* Entity转TreeNode工具类
* 用法:继承该类,并实现convert(E entity, T view)方法
*
* @param <E> Entity
* @param <T> TreeNode
*/
public abstract class ConvertTreeNodeUtils<E, T extends ExTreeNode> {
protected Class<T> viewClass;
private LinkedHashMap<String, T> retp = new LinkedHashMap<String, T>();
@SuppressWarnings("unchecked")
public ConvertTreeNodeUtils() {
viewClass = (Class) TypeUtil.getTypeArgument(getClass(), 1);
}
/**
* 将Entity转换为TreeNode
* @param entity 要转换的Entity对象
*/
public T transTreeNode(E entity) {
try {
T node = viewClass.newInstance();
if (entity != null) {
convert(entity, node);
}
return node;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将Entity集合转换为TreeNode集合
* @param list 要转换的Entity集合
*/
public List<T> transTreeNode(List<E> list) {
int size = list != null ? list.size() : 0;
List<T> result = new ArrayList<>(size);
try {
for (int i = 0; i < size; i++) {
E entity = list.get(i);
T node = viewClass.newInstance();
convert(entity, node);
result.add(node);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 将Entity集合转换为TreeNode集合,静态树
* @param list 要转换的Entity集合
*/
public List<T> transStaticTree(List<E> list) {
return transStaticTree(list, null, null);
}
/**
* 将Entity集合转换为TreeNode集合,静态树
* @param list 要转换的Entity集合
* @param checkedOidSet 已选择的节点OID集合
*/
public List<T> transStaticTree(List<E> list, Set<String> checkedOidSet) {
return transStaticTree(list, null, checkedOidSet);
}
/**
* 将Entity集合转换为TreeNode集合,静态树
* @param list 要转换的Entity集合
* @param root 添加一个根节点
* @param checkedOidSet 已选择的节点OID集合
*/
public List<T> transStaticTree(List<E> list, T root, Set<String> checkedOidSet) {
int size = list != null ? list.size() : 0;
ArrayList<T> treeNodes;
if(null != root){
treeNodes = new ArrayList<T>(size + 1);
root.setParentId(null);
treeNodes.add(root);
}else{
treeNodes = new ArrayList<>(size);
}
try {
for (int i = 0; i < size; i++) {
E entity = list.get(i);
T node = viewClass.newInstance();
convert(entity, node);
if(node.getId() == null){
throw new Exception("TreeNode id is null");
}
nodeCheck(node, checkedOidSet);
if(null != root && node.getId().equals(root.getId())){//根节点
//此时根节点已在treeNodes中,不能再次加入
}else{
treeNodes.add(node);
}
if(node.getParentId() != null && !node.getParentId().equals("0")){
retp.put(node.getId(), node);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return transStaticTree(treeNodes);
}
/**
* 将TreeNode集合生成静态树,静态树
* @param list 要转换的TreeNode集合
*/
private List<T> transStaticTree(ArrayList<T> list) {
int size = list != null ? list.size() : 0;
if(retp.size() < 1){
for (int i = 0; i < size; i++) {
T node = list.get(i);
if(node.getParentId() != null && !node.getParentId().equals("0")){
retp.put(node.getId(), node);
}
}
}
List<T> completeTree = new ArrayList<T>();
for (int i = 0; i < size; i++) {
T node = list.get(i);
if (node.getParentId() == null || node.getParentId().equals("0")) {
node = node.buildTree(node, retp);
completeTree.add(node);
}
}
retp.clear();
return completeTree;
}
/**
* 自定义转换
* @param entity Entity对象
* @param node TreeNode对象
*/
public abstract void convert(E entity, T node);
/**
* 设置节点是否选中
* 子类可自行重写
* @param node 节点
* @param checkedOidSet 选中的ID集合
*/
public void nodeCheck(T node, Set<String> checkedOidSet){
}
}
package com.app.framework.core.support.convert;
import cn.hutool.core.util.TypeUtil;
import org.springframework.beans.BeanUtils;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
/**
* Entity转View工具类
* 用法:继承该类,并实现convert(E entity, V view)方法
*
* @param <E> Entity
* @param <V> View
*/
public abstract class ConvertViewUtils<E, V> {
protected Class<V> viewClass;
@SuppressWarnings("unchecked")
public ConvertViewUtils() {
viewClass = (Class) TypeUtil.getTypeArgument(getClass(), 1);
}
/**
* 将实体E转换成View,可忽略属性
* 返回页面时进行数据转换
* @param entity 需要转换的Entity
*/
public V transform(E entity) {
try {
V view = viewClass.newInstance();
if (entity != null) {
BeanUtils.copyProperties(entity, view);
convert(entity, view);
}
return view;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将实体E转换成View,可忽略属性
* 返回页面时进行数据转换
* @param entity 需要转换的Entity
* @param ignoreProperties 需要忽略的属性
*/
public V transform(E entity, String... ignoreProperties) {
try {
V view = viewClass.newInstance();
if (entity != null) {
BeanUtils.copyProperties(entity, view, ignoreProperties);
convert(entity, view);
}
return view;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 将实体E的集合转换成View的集合,可忽略属性
*
* @param list 需要转换的数据集合
*/
public List<V> transform(List<E> list){
int size = list != null ? list.size() : 0;
List<V> result = new ArrayList<>(size);
try {
for (int i = 0; i < size; i++) {
E entity = list.get(i);
V view = viewClass.newInstance();
BeanUtils.copyProperties(entity, view);
convert(entity, view);
result.add(view);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 将实体E的集合转换成View的集合,可忽略属性
*
* @param list 需要转换的数据集合
* @param ignoreProperties 需要忽略的属性, 可选参数
*/
public List<V> transform(List<E> list, String... ignoreProperties) {
int size = list != null ? list.size() : 0;
List<V> result = new ArrayList<>(size);
try {
for (int i = 0; i < size; i++) {
E entity = list.get(i);
V view = viewClass.newInstance();
BeanUtils.copyProperties(entity, view, ignoreProperties);
convert(entity, view);
result.add(view);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 自定义转换(基类中已实现实体E到V的转换,该方法只需要实现其他附加的转换功能即可)
* @param entity 实体类对象
* @param view View对象
*/
public abstract void convert(E entity, V view) throws ParseException;
}
package com.app.framework.core.support.enums;
import com.app.framework.core.support.enums.data.EnumItem;
import com.app.framework.core.support.enums.data.EnumItemPool;
import org.apache.commons.lang.StringUtils;
import java.io.Serializable;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
/**
* 枚举基类,提供枚举常用的方法
* 提供实例方法:getValue、getText、equalValue、isNotEquals
* 提供静态方法:getByValue、getByText、getTextByValue
*
* @param <K> value数据类型
*/
public interface BaseEnum<K extends Serializable> {
default void putEnumItem(K value, String text) {
EnumItemPool.putEnumItem(this, value, text);
}
default EnumItem getEnumItem() {
return EnumItemPool.getEnumItem(this);
}
default K getValue() {
return (K) getEnumItem().getValue();
}
default String getText() {
return getEnumItem().getText();
}
/**
* 当前对象的 value 是否 和参数中的 value 相等
*
* @param value
* @return
*/
default boolean equalValue(K value) {
return this.getValue().equals(value);
}
/**
* 当前对象是否和已知对象不等
*
* @param item
* @return
*/
default boolean isNotEquals(BaseEnum item) {
return this != item;
}
/**
* 通过 value 获取指定 枚举类型中的 枚举对象
*
* @param enumClass
* @param value
* @param <T>
* @return
*/
static <T extends BaseEnum> T getByValue(Class<T> enumClass, Serializable value) {
if (Objects.isNull(value)) {
return null;
}
return Stream.of(enumClass.getEnumConstants()).filter(x -> x.getValue().equals(value)).findAny().orElse(null);
}
/**
* 通过 text 获取指定 枚举类型中的 枚举对象
*
* @param enumClass 枚举类
* @param text
* @param <T>
* @return
*/
static <T extends BaseEnum> T getByText(Class<T> enumClass, String text) {
if (Objects.isNull(text)) {
return null;
}
return Stream.of(enumClass.getEnumConstants()).filter(x -> x.getText().equals(text)).findAny().orElse(null);
}
/**
* 通过 value 获取指定 枚举类型中的 text
*
* @param enumClass
* @param value
* @param <T>
* @return
*/
static <T extends BaseEnum> String getTextByValue(Class<T> enumClass, Serializable value) {
return Optional.ofNullable(getByValue(enumClass, value)).map(BaseEnum::getText).orElse(StringUtils.EMPTY);
}
}
package com.app.framework.core.support.enums.common;
import com.app.framework.core.support.enums.BaseEnum;
import com.app.framework.core.support.enums.dict.DictEnum;
/**
* 性别枚举
* 性别(0-女 1-男 2-保密)
*/
@DictEnum(type = "genderEnum", desc = "性别")
public enum GenderEnum implements BaseEnum<Integer> {
MAN(1, "男"), WOMAN(0, "女"), BAOMI(2, "保密");
GenderEnum(Integer value, String text) {
putEnumItem(value, text);
}
}
package com.app.framework.core.support.enums.common;
import com.app.framework.core.support.enums.BaseEnum;
/**
* 平台枚举
* 平台(ALL-全站 IOS-IOS ANDROID-安卓 3-web站 WAP-wap站)
*/
public enum PlatformEnum implements BaseEnum<String> {
ALL("ALL", "全站"), IOS("IOS", "IOS"), ANDROID("ANDROID", "安卓"), WEB("WEB", "web站"), WAP("WAP", "wap站");
PlatformEnum(String value, String text) {
putEnumItem(value, text);
}
}
package com.app.framework.core.support.enums.common;
import com.app.framework.core.support.enums.BaseEnum;
import com.app.framework.core.support.enums.dict.DictEnum;
/**
* 状态枚举
* 状态(1-启用 2-禁用 3-删除)
*/
@DictEnum(desc = "状态")
public enum StateEnum implements BaseEnum<Integer> {
NORMAL(1, "启用"), DISABLE(2, "禁用"), DELETE(3, "删除");
StateEnum(Integer value, String text) {
putEnumItem(value, text);
}
}
package com.app.framework.core.support.enums.data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
/**
* 枚举项
*/
@Setter
@Getter
@ToString
public class EnumItem implements Serializable {
private Serializable value;
private String text;
public EnumItem(Serializable value, String text) {
this.value = value;
this.text = text;
}
}
package com.app.framework.core.support.enums.data;
import com.app.framework.core.support.enums.BaseEnum;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 存储枚举数据
*/
public class EnumItemPool {
private EnumItemPool() {}
/**
* 用于存储枚举数据
*/
private static final Map<BaseEnum, EnumItem> enumItemMap = new ConcurrentHashMap<>();
/**
* 往 map 中添加枚举项
*/
public static <K extends Serializable> void putEnumItem(BaseEnum baseEnum, K value, String label) {
enumItemMap.put(baseEnum, new EnumItem(value, label));
}
/**
* 获取静态数据
*/
public static EnumItem getEnumItem(BaseEnum baseEnum) {
return enumItemMap.get(baseEnum);
}
}
package com.app.framework.core.support.enums.dict;
import java.lang.annotation.*;
/**
* 用于标记枚举需转换为字典使用
*/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DictEnum {
/**
* 字典标识
*/
String type() default "";
/**
* 字典标识名称
*/
String desc() default "";
}
package com.app.framework.core.support.enums.dict;
import com.app.framework.core.support.enums.data.EnumItem;
import lombok.Data;
import java.util.List;
/**
* 枚举转字典使用
*/
@Data
public class DictMgt {
/**
* 字典标识
*/
private String type;
/**
* 字典标识名称
*/
private String desc;
/**
* 字典值列表
*/
private List<EnumItem> dictItemList;
}
package com.app.framework.core.support.enums.dict.config;
import cn.hutool.core.map.MapUtil;
import com.app.framework.core.support.enums.BaseEnum;
import com.app.framework.core.support.enums.data.EnumItem;
import com.app.framework.core.support.enums.dict.DictEnum;
import com.app.framework.core.support.enums.dict.DictMgt;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.stream.Collectors;
@Component
public class DictEnumConfig implements InitializingBean {
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private Environment environment;
private static Map<String, DictMgt> dictMap = new HashMap<>();
public static Map<String, DictMgt> getDictMap() {
return dictMap;
}
public static DictMgt getDict(String type) {
return dictMap.get(type);
}
public static List<EnumItem> getDictItem(String type) {
DictMgt dictMgt = getDict(type);
return dictMgt != null ? dictMgt.getDictItemList() : null;
}
@Override
public void afterPropertiesSet() throws ClassNotFoundException {
String basePackage = "com.app";
// 创建scanner
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(resourceLoader);
// 设置扫描器scanner扫描的过滤条件
AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(DictEnum.class);
scanner.addIncludeFilter(annotationTypeFilter);
// 通过scanner获取basePackage下的候选类(有标@SimpleRpcClient注解的类)
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
// 遍历每一个候选类
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(DictEnum.class.getCanonicalName());
final Class<?> cls = Class.forName(beanDefinition.getBeanClassName());
BaseEnum[] enumConstants = (BaseEnum[]) cls.getEnumConstants();
List<EnumItem> dictItemList = Arrays.stream(enumConstants).map(e -> {
return new EnumItem(e.getValue(), e.getText());
}).collect(Collectors.toList());
DictMgt dictMgt = new DictMgt();
dictMgt.setType(StringUtils.defaultIfBlank(MapUtil.getStr(attributes, "type"), StringUtils.uncapitalize(cls.getSimpleName())));
dictMgt.setDesc(MapUtil.getStr(attributes, "desc"));
dictMgt.setDictItemList(dictItemList);
dictMap.put(dictMgt.getType(), dictMgt);
}
}
}
/**
* 创建扫描器
*/
protected ClassPathScanningCandidateComponentProvider getScanner() {
return new ClassPathScanningCandidateComponentProvider(false, environment) {
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
boolean isCandidate = false;
if (beanDefinition.getMetadata().isIndependent()) {
if (!beanDefinition.getMetadata().isAnnotation()) {
isCandidate = true;
}
}
return isCandidate;
}
};
}
}
package com.app.framework.core.support.filter;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.util.StringUtils;
/**
* Spring MVC 时间转换
*/
public class DateConvertEditor extends PropertyEditorSupport {
private SimpleDateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasText(text)) {
try {
if (text.indexOf(":") > 0) {
if(text.length() == 16){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
setValue(sdf.parse(text));
}else if(text.length() == 19){
setValue(this.datetimeFormat.parse(text));
}else if(text.length() == 21){
setValue(this.datetimeFormat.parse(text));
}else{
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
setValue(sdf.parse(text));
}
} else if (text.indexOf("-") > 0) {
if(text.length() == 7){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
setValue(sdf.parse(text));
}else if(text.length() == 10){
setValue(this.dateFormat.parse(text));
}else{
setValue(null);
}
} else {
Long time = Long.parseLong(text);
setValue(datetimeFormat.parse(datetimeFormat.format(new Date(time))));
}
} catch (ParseException ex) {
IllegalArgumentException iae = new IllegalArgumentException("Could not parse date: " + ex.getMessage());
iae.initCause(ex);
throw iae;
}
} else {
setValue(null);
}
}
}
package com.app.framework.core.support.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* Mapper公共基类,请勿修改
* @param <T> The Model Class 这里是泛型不是Model类
*/
public interface CrudBaseMapper<T> extends BaseMapper<T> {
}
\ No newline at end of file
package com.app.framework.core.support.resubmit;
import java.lang.annotation.*;
/**
* 重复提交注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Resubmit {
/**
* 支持两种形式:一个是方法参数,一个是令牌
*/
enum Type { PARAM, TOKEN }
/**
* 默认防重提交,是方法参数
* @return
*/
Type type() default Type.PARAM;
/**
* 延时时间 在延时多久后可以再次提交
*
* @return Time unit is one second
*/
int delaySeconds() default 3;
}
package com.app.framework.core.support.resubmit;
import cn.hutool.core.util.IdUtil;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 防重复提交锁
*/
public interface ResubmitLock {
/**
* 防重复提交令牌的缓存key
*/
String RESUBMIT_TOKEN_KEY = "resubmit-token:%s:%s";
/**
* resubmit-token 过期时间,防止数据永不过期
*/
Integer EXPIRE_TIME_MINUTE = 30;
ConcurrentHashMap<String, Object> LOCK_CACHE = new ConcurrentHashMap<>(200);
ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(5, new ThreadPoolExecutor.DiscardPolicy());
/**
* 参数形式防重提交 putIfAbsent 是原子操作保证线程安全
*
* @param key 对应的key
* @param value
* @param delaySeconds 延时时间
* @return
*/
default boolean lock(final String key, Object value, final int delaySeconds) {
boolean lock = Objects.isNull(LOCK_CACHE.putIfAbsent(key, value));
if (lock) {
EXECUTOR.schedule(() -> {
LOCK_CACHE.remove(key);
}, delaySeconds, TimeUnit.SECONDS);
}
return lock;
}
/**
* 参数形式防重提交 用以控制短时间内的重复提交
*
* @param lock 是否需要解锁
* @param key 对应的key
*/
default void unLock(final boolean lock, final String key) {
if (lock) {
LOCK_CACHE.remove(key);
}
}
/**
* 令牌形式防重复提交,生成令牌
*
* @param username 登录用户
* @return
*/
default String tokenCreate(final String username) {
String token = IdUtil.randomUUID();
String key = String.format(RESUBMIT_TOKEN_KEY, username, token);
boolean lock = Objects.isNull(LOCK_CACHE.put(key, username));
if (lock) {
EXECUTOR.schedule(() -> {
LOCK_CACHE.remove(key);
}, EXPIRE_TIME_MINUTE, TimeUnit.MINUTES);
}
return token;
}
/**
* 令牌形式防重复提交,删除令牌
*
* @param username 登录用户
* @return
*/
default boolean tokenDelete(final String username, final String token) {
String key = String.format(RESUBMIT_TOKEN_KEY, username, token);
Object o = LOCK_CACHE.remove(key);
return !Objects.isNull(o);
}
}
package com.app.framework.core.support.resubmit.aspect;
import cn.hutool.crypto.SecureUtil;
import com.app.framework.core.support.auth.LoginUser;
import com.app.framework.core.support.resubmit.Resubmit;
import com.app.framework.core.support.resubmit.ResubmitLock;
import com.app.framework.core.support.view.form.AjaxResult;
import com.app.framework.core.utils.request.RequestUtil;
import com.app.framework.core.utils.request.SessionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
/**
* 重复提交校验
**/
@Slf4j
@Aspect
@Component
public class ResubmitAspect {
private final static Object PRESENT = new Object();
@Resource
ResubmitLock resubmitLock;
public String buildKey(Method method, LoginUser loginUser) {
String ip = RequestUtil.getIpAddr(RequestUtil.getRequest());
//目标类、方法
String className = method.getDeclaringClass().getName();
String methodName = method.getName();
return "resubmit:" + SecureUtil.md5(String.format("%s-%s-%s-%s", ip, className, methodName, loginUser.getUsername()));
}
@Around("execution(public * *(..)) && @annotation(com.app.framework.core.support.resubmit.Resubmit)")
public Object handleResubmit(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = RequestUtil.getRequest();
LoginUser loginUser = SessionUtil.getCurrentUser(request);
if (loginUser == null) {
loginUser = (LoginUser) request.getAttribute("apiLoginUser");
}
if (loginUser == null) {//放行
return joinPoint.proceed();
}
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//执行锁
boolean lock = false;
//通过反射技术来获取注解对象
Resubmit resubmit = method.getAnnotation(Resubmit.class);
//防重提交类型
String type = resubmit.type().name();
if (type.equalsIgnoreCase(Resubmit.Type.PARAM.name())) {
//方式一,参数形式防重提交
int delaySeconds = resubmit.delaySeconds();
if (delaySeconds <= 0) {//放行
return joinPoint.proceed();
}
String key = this.buildKey(method, loginUser);
lock = resubmitLock.lock(key, PRESENT, delaySeconds);
} else {
//方式二,令牌形式防重提交
String resubmitToken = request.getHeader("resubmit-token");
if (StringUtils.isBlank(resubmitToken)) {
resubmitToken = request.getParameter("resubmit-token");
}
if (StringUtils.isBlank(resubmitToken)) {
return AjaxResult.wrapError("防重复提交令牌不能为空");
}
//提交表单的token key,直接删除成功则说明token正确
lock = resubmitLock.tokenDelete(loginUser.getUsername(), resubmitToken);
}
if (lock) {
//放行
return joinPoint.proceed();
} else {
//响应重复提交异常
return AjaxResult.wrap("resubmit", "请勿重复提交");
}
}
}
package com.app.framework.core.support.service;
import com.app.framework.core.support.view.grid.Paging;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
/**
* 公共Service接口定义
* 所有定义的Service接口若要使用基类方法都必须继承此类
* 只能通过继承的方式使用
*/
public interface CrudBaseService<T> extends IService<T> {
default List<T> getPageList(T view, Paging paging) {
return null;
}
}
\ No newline at end of file
package com.app.framework.core.support.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* ID生成接口
*/
public interface SequenceService {
/**
* 锁对象,可以为任意对象
*/
Object lockObj = "lockerOrder";
/**
* 订单号生成计数器
* <prefix, 计数器>
*/
Map<String, Long> IdCountMap = new HashMap<>();
/**
* 每毫秒生成订单号数量最大值
*/
int maxPerMSECSize = 100000;
/**
* 根据yyMMdd生成非重复ID
* @param prefix ID前缀
* @return
*/
default String genIdByDate(String prefix) {
String p = ObjectUtil.defaultIfNull(prefix, "id");
// 最终生成的订单号
String finOrderNum = "";
synchronized (lockObj) {
Long idCount = ObjectUtil.defaultIfNull(IdCountMap.get(p), 0L);
// 计数器到最大值归零,可扩展更大
if (idCount > maxPerMSECSize) {
idCount = 0L;
}
idCount++;
// 组装订单号
finOrderNum = ObjectUtil.defaultIfNull(prefix, "") + DateUtil.format(new Date(), "yyMMdd") + (maxPerMSECSize + idCount);
IdCountMap.put(p, idCount);
}
return finOrderNum;
}
}
package com.app.framework.core.support.service.impl;
import com.app.framework.core.support.mapper.CrudBaseMapper;
import com.app.framework.core.support.service.CrudBaseService;
import com.app.framework.core.support.view.grid.Paging;
import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.ColumnCache;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang.StringUtils;
import java.util.List;
import java.util.Map;
import static com.baomidou.mybatisplus.core.enums.SqlKeyword.*;
/**
* Service实现类的基类
*
* @param <M>
* @param <T>
*/
public class CrudBaseServiceSupport<M extends CrudBaseMapper<T>, T> extends ServiceImpl<M, T> implements CrudBaseService<T> {
/**
* 设置排序
*
* @param wrapper
* @param paging
*/
private void setOrderBy(Wrapper<T> wrapper, Paging paging) {
if (wrapper == null || paging == null || StringUtils.isBlank(paging.getSort())) {
return;
}
wrapper.getExpression().getOrderBy().clear();
Map<String, ColumnCache> columnMap = LambdaUtils.getColumnMap(entityClass);
String sorts[] = paging.getSort().split(",");
String dirs[] = null;
if (StringUtils.isNotBlank(paging.getDir())) {
dirs = paging.getDir().split(",");
}
for (int i = 0; i < sorts.length; i++) {
String column = sorts[i], dir = "ASC";
if (dirs != null && dirs.length > i) {
dir = dirs[i].toUpperCase();
}
ColumnCache columnCache = columnMap.get(LambdaUtils.formatKey(column));
if (columnCache == null) {
columnCache = columnMap.values().stream().filter(e -> e.getColumn().equals(column)).findFirst().get();
}
if (columnCache == null) {
throw new RuntimeException("数据库中找不到 " + column + " 映射字段");
}
String sqlColumn = columnCache.getColumn();
ISqlSegment[] sqlSegments = {ORDER_BY, () -> sqlColumn, "DESC".equals(dir) ? DESC : ASC};
wrapper.getExpression().add(sqlSegments);
}
}
/**
* 分页查询
* @param wrapper 查询条件
* @param paging 分页条件
* @return
*/
public List<T> pageList(Wrapper<T> wrapper, Paging paging) {
this.setOrderBy(wrapper, paging);
if (Paging.isPage(paging)) {
Page<T> page = new Page<>(paging.getPageNo(), paging.getLimit(), paging.getIsCountPage());
Page<T> result = this.page(page, wrapper);
Paging.setPage(paging, result);
return result.getRecords();
}
return this.list(wrapper);
}
}
package com.app.framework.core.support.view.form;
import cn.hutool.core.codec.Base64;
import cn.hutool.json.JSONUtil;
import java.util.Date;
/**
* 请求返回结果
* code(200:成功 0或其他:失败)
*/
public class AjaxResult<T> {
/**
* 执行成功
*/
public static final String SUCCESS = "200";
/**
* 执行失败
*/
public static final String FAILURE = "0";
/**
* 执行结果(200: 成功 0或其它: 失败 401: 身份认证失败)
*/
private String code;
/**
* 提示信息
*/
private String msg = "";
/**
* 数据
*/
private T data;
/**
* 时间
*/
private Date time;
/**
* 获取执行结果
*
* @return true:执行成功,code代码为200 false:执行失败,code代码非200
*/
public boolean success() {
if (SUCCESS.equals(this.code))
return true;
return false;
}
/**
* 获取执行结果
*
* @return 执行结果代码,200:成功 0:失败 其它:自定义的失败代码
*/
public String getCode() {
return code;
}
/**
* 设置执行结果
*
* @param code 执行结果代码
*/
public void setCode(String code) {
this.code = code;
}
/**
* 设置执行结果
*
* @param success 执行结果
*/
public void setCode(boolean success) {
if (success)
this.code = SUCCESS;
else
this.code = FAILURE;
}
/**
* 获取提示信息
*/
public String getMsg() {
if (msg == null || "".equals(msg)) {
if (SUCCESS.equals(this.code)) {
msg = "操作成功";
} else {
msg = "操作失败";
}
}
return msg;
}
/**
* 设置提示信息
*
* @param msg 提示信息
*/
public void setMsg(String msg) {
this.msg = msg;
}
/**
* 获取返回数据
*/
public T getData() {
return data;
}
/**
* 设置返回数据
*
* @param data 返回数据
*/
public void setData(T data) {
this.data = data;
}
/**
* 获取数据返回时间
*/
public Date getTime() {
if (this.time == null) {
this.time = new Date();
}
return time;
}
/**
* 设置数据返回时间
*/
public void setTime(Date time) {
this.time = time;
}
/**
* 实例化AjaxResult对象
*
* @param success 执行结果
*/
public static AjaxResult wrap(boolean success) {
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.setCode(success);
return ajaxResult;
}
/**
* 实例化AjaxResult对象
*
* @param success 执行结果
* @param msg 提示信息
*/
public static AjaxResult wrap(boolean success, String msg) {
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.setCode(success);
ajaxResult.setMsg(msg);
return ajaxResult;
}
/**
* 实例化AjaxResult对象
*
* @param success 执行结果
* @param msg 提示信息
* @param data 返回数据
*/
public static <T> AjaxResult wrap(boolean success, String msg, T data) {
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.setCode(success);
ajaxResult.setMsg(msg);
ajaxResult.setData(data);
return ajaxResult;
}
/**
* 实例化执行成功的AjaxResult对象
*
* @param msg 提示信息
*/
public static AjaxResult wrapSuccess(String msg) {
return AjaxResult.wrap(true, msg);
}
/**
* 实例化执行失败的AjaxResult对象
*
* @param msg 提示信息
*/
public static AjaxResult wrapError(String msg) {
return AjaxResult.wrap(false, msg);
}
/**
* 实例化执行成功的AjaxResult对象
*
* @param data 返回数据
*/
public static <T> AjaxResult wrapData(T data) {
return AjaxResult.wrap(true, null, data);
}
/**
* 实例化AjaxResult对象
*
* @param code 执行结果
* @param msg 提示信息
*/
public static AjaxResult wrap(String code, String msg) {
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.setCode(code);
ajaxResult.setMsg(msg);
return ajaxResult;
}
/**
* 实例化AjaxResult对象
*
* @param code 执行结果
* @param msg 提示信息
* @param data 返回数据
*/
public static <T> AjaxResult wrap(String code, String msg, T data) {
AjaxResult ajaxResult = new AjaxResult();
ajaxResult.setCode(code);
ajaxResult.setMsg(msg);
ajaxResult.setData(data);
return ajaxResult;
}
/**
* 实例化AjaxResult对象,并对data进行Base64加密
*
* @param success 执行结果
* @param data 返回数据
*/
public static <T> AjaxResult wrapBase64(boolean success, T data) {
//对返回的data数据进行Base64加密
if (data != null) {
if (data instanceof String) {
data = (T) Base64.encode(data.toString());
} else {
String jsonData = JSONUtil.parseObj(data, false).toString();
data = (T) Base64.encode(jsonData);
}
}
return AjaxResult.wrap(success, null, data);
}
}
package com.app.framework.core.support.view.form;
import org.apache.commons.lang.StringUtils;
/**
* 模型编辑form
*/
public class ModelEditForm {
/**
* 菜单Id
*/
private Long moduleId;
/**
* 编辑类型
* edit or view
*/
private String editType;
/**
* 列表页面的页码
*/
private Integer pageNumber;
/**
* tab选项卡索引
*/
private Integer tabIndex;
public Long getModuleId() {
return moduleId;
}
public void setModuleId(Long moduleId) {
this.moduleId = moduleId;
}
public String getEditType() {
if(StringUtils.isBlank(editType)){
editType = "edit";
}
return editType;
}
public void setEditType(String editType) {
this.editType = editType;
}
public Integer getPageNumber() {
return pageNumber;
}
public void setPageNumber(Integer pageNumber) {
this.pageNumber = pageNumber;
}
public Integer getTabIndex() {
return tabIndex;
}
public void setTabIndex(Integer tabIndex) {
this.tabIndex = tabIndex;
}
}
package com.app.framework.core.support.view.grid;
import java.util.Collection;
/**
* Grid使用
*/
public class ExGridLoad {
/**总记录*/
private Long totalCount;
/**总页数*/
private Long totalPage;
/**数据集合*/
private Collection<?> result;
/**
* 获取总记录数
*/
public Long getTotalCount() {
return totalCount;
}
/**
* 设置总记录数
* @param totalCount 总记录数
*/
public void setTotalCount(Long totalCount) {
this.totalCount = totalCount;
}
/**
* 获取总页数
*/
public Long getTotalPage() {
return totalPage;
}
/**
* 设置总页数
* @param totalPage 总页数
*/
public void setTotalPage(Long totalPage) {
this.totalPage = totalPage;
}
/**
* 实例化ExGridLoad对象
* @param list 数据集合
* @param page 分页对象
*/
public static ExGridLoad wrapExGridLoad(Collection<?> list, Paging page) {
Long totalCount = page.getTotalCount();
if(totalCount == null || totalCount <= 0)totalCount = new Long(list.size());
ExGridLoad exGridLoad = new ExGridLoad();
exGridLoad.setTotalCount(totalCount);
exGridLoad.setTotalPage(page.getTotalPage());
exGridLoad.setResult(list);
return exGridLoad;
}
/**
* 实例化ExGridLoad对象
* @param list 数据集合
*/
public static ExGridLoad wrapExGridLoad(Collection<?> list) {
ExGridLoad exGridLoad = new ExGridLoad();
exGridLoad.setResult(list);
return exGridLoad;
}
/**
* 计算总页数
* @param totalCount 总记录数
* @param limit 每页显示记录数
* @return 总页数
*/
public static Long getTotalPage(Long totalCount, Integer limit){
if(totalCount !=null && limit != null){
return (totalCount + limit-1) / limit;
}
return 1l;
}
/**
* 获取数据集合
*/
public Collection<?> getResult() {
return result;
}
/**
* 设置数据集合
* @param result 数据集合
*/
public void setResult(Collection<?> result) {
this.result = result;
}
}
package com.app.framework.core.support.view.grid;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.io.Serializable;
/**
* 分页参数对象
* 包含排序字段和排序方式
*/
public class Paging implements Serializable{
private static final long serialVersionUID = 2837480041430890963L;
/**
* 构造函数
*/
public Paging(){}
/**
* 有参构造函数
* @param isPage 是否分页
*/
public Paging(Boolean isPage){
this.isPage = isPage;
}
/**
* 有参构造函数
* @param pageNo 当前页码
* @param limit 每页显示记录数
*/
public Paging(Integer pageNo, Integer limit){
this.pageNo = pageNo;
this.limit = limit;
}
/**当前页码*/
private Integer pageNo = null;
/**起始记录数*/
private Integer start = null;
/**每页显示记录数*/
private Integer limit = 10;
/**排序方式(desc || asc),多个用","分隔(与sort的每个字段对应)*/
private String dir;
/**排序字段,多个字段用","分隔*/
private String sort;
/**查询参数*/
private Object queryPara;
/**总记录数*/
private Long totalCount;
/**总页数*/
private Long totalPage;
/**是否分页*/
private Boolean isPage = true;
/**是否查询总记录数*/
private Boolean isCountPage = true;
public String toString(){
return "Page [当前页码=" + pageNo + ", 起始记录数=" + start + ", 每页显示记录数=" + limit + ", 排序字段=" + sort + ", 排序方式=" + dir + ", 是否分页=" + isPage + ", 是否查询总记录数=" + isCountPage + "]";
}
/**
* 获取起始记录数
*/
public Integer getStart() {
if(start == null && pageNo != null && limit != null){
//根据页码计算起始记录数
start = (pageNo-1) * limit;
}
if(start == null)start = 0;
return start;
}
/**
* 获取每页显示记录数
*/
public Integer getLimit() {
if(limit == null)limit = 10;
return limit;
}
/**
* 获取排序方式
*/
public String getDir() {
return dir;
}
/**
* 获取排序字段
*/
public String getSort() {
return sort;
}
/**
* 设置起始记录数
* @param start
*/
public void setStart(Integer start) {
this.start = start;
}
/**
* 设置每页显示记录数
* @param limit
*/
public void setLimit(Integer limit) {
this.limit = limit;
}
/**
* 设置排序方式
* @param dir
*/
public void setDir(String dir) {
this.dir = dir;
}
/**
* 设置排序字段
* @param sort
*/
public void setSort(String sort) {
this.sort = sort;
}
/**
* 获取查询参数
*/
public Object getQueryPara() {
return queryPara;
}
/**
* 设置查询参数
* @param queryPara
*/
public void setQueryPara(Object queryPara) {
this.queryPara = queryPara;
}
/**
* 获取总记录数
*/
public Long getTotalCount() {
return totalCount;
}
/**
* 设置总记录数
* @param totalCount
*/
public void setTotalCount(Long totalCount) {
this.totalCount = totalCount;
}
/**
* 获取是否分页
*/
public Boolean getIsPage() {
if(isPage == null)isPage = false;
return isPage;
}
/**
* 设置是否分页
* @param isPage
*/
public void setIsPage(Boolean isPage) {
if(isPage == null)isPage = false;
this.isPage = isPage;
if(false == isPage){
this.isCountPage = false;
}
}
/**
* 获取是否计算总记录数
*/
public Boolean getIsCountPage() {
if(isCountPage == null)isCountPage = false;
return isCountPage;
}
/**
* 设置是否计算总记录数
* @param isCountPage
*/
public void setIsCountPage(Boolean isCountPage) {
this.isCountPage = isCountPage;
}
/**
* 获取当前显示的页码
*/
public Integer getPageNo() {
if(pageNo == null && start != null && limit != null){
//根据起始记录数计算当前页码
pageNo = (start/limit) + 1;
}
if(pageNo == null)pageNo = 1;
return pageNo;
}
/**
* 设置当前显示的页码
* @param pageNo
*/
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
/**
* 获取总页数
*/
public Long getTotalPage() {
if(totalCount !=null && limit != null && limit > 0){
totalPage = (totalCount + limit-1) / limit;
}
return totalPage;
}
/**
* 设置总页数
* @param totalPage
*/
public void setTotalPage(Long totalPage) {
this.totalPage = totalPage;
}
/**
* 判断是否分页
* @param paging 分页对象
* @return true:分页 false:不分页
*/
public static boolean isPage(Paging paging){
if(paging != null && paging.getIsPage()){
return true;
}
return false;
}
/**
* 判断是否查询总记录数
* @param paging 分页对象
* @return true:查询总记录数 false:不查询总记录数
*/
public static boolean isCountPage(Paging paging){
if(paging != null && paging.getIsCountPage()){
return true;
}
return false;
}
/**
* 设置Mybatis分页插件返回Page对象
* @param page
* @return Paging
*/
public static Paging setPage(Paging paging, Page page){
if(paging == null){
paging = new Paging(false);
}
paging.setTotalPage(page.getPages());
paging.setTotalCount(page.getTotal());
return paging;
}
/**
* 判断是否分页
* @param paging 分页对象
* @return true:分页 false:不分页
*/
public static Page page(Paging paging){
if(paging != null && paging.getIsPage()){
return new Page<>(paging.getPageNo(), paging.getLimit());
}
return new Page<>(1, -1);
}
}
package com.app.framework.core.support.view.grid;
import org.apache.commons.lang.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
/**
* 分页参数工具类
* 主要是从HttpServletRequest中获取分页参数
* 用法:Paging paging = PagingUtils.getPaging(request);
*/
public class PagingUtils {
/**
* 从request对象中获取分页参数、排序参数
* @param request
* @return Page
*/
public static Paging getPaging(HttpServletRequest request){
return getPaging(request, null);
}
/**
* 从request对象中获取分页参数、排序参数
* @param request
* @param limit 每页显示记录数(用于设置每页显示记录数)
* @return Page
*/
public static Paging getPaging(HttpServletRequest request, Integer limit){
Paging page = new Paging();
Enumeration<?> paramNames = request.getParameterNames();
while (paramNames != null && paramNames.hasMoreElements()) {
String paramName = (String) paramNames.nextElement();
if("pageNo".equals(paramName)){
String pageNo = request.getParameter("pageNo");
if(StringUtils.isNotBlank(pageNo)){
page.setPageNo(Integer.parseInt(pageNo));
}
}else if("start".equals(paramName)){
String start = request.getParameter("start");
if(StringUtils.isNotBlank(start)){
page.setStart(Integer.parseInt(start));
}
}else if("limit".equals(paramName)){
String slimit = request.getParameter("limit");
if(StringUtils.isNotBlank(slimit)){
page.setLimit(Integer.parseInt(slimit));
}
}else if("isPage".equals(paramName)){
String isPage = request.getParameter("isPage");
if(StringUtils.isNotBlank(isPage)){
page.setIsPage(Boolean.parseBoolean(isPage));
}
}else if("isCountPage".equals(paramName)){
String isCountPage = request.getParameter("isCountPage");
if(StringUtils.isNotBlank(isCountPage)){
page.setIsCountPage(Boolean.parseBoolean(isCountPage));
}
}else if("sort".equals(paramName)){
String sort = request.getParameter("sort");
if(StringUtils.isNotBlank(sort)){
page.setSort(sort);
}
}else if("dir".equals(paramName)){
String dir = request.getParameter("dir");
if(StringUtils.isNotBlank(dir)){
page.setDir(dir);
}
}
}
if(limit != null){
page.setLimit(limit);
}
return page;
}
}
package com.app.framework.core.support.view.tree;
import java.io.Serializable;
import java.util.*;
/**
* TreeNode基类
*/
public class ExTreeNode implements Serializable {
/**节点ID*/
private String id;
/**父节点ID*/
private String parentId;
/**节点名称*/
private String name;
/**
* 子节点集合
*/
private List children;
/**
* 生成Tree
* 当构建节点的数据不在一张表时,ParentId和Id可能会一样,导致报错,此时需处理下
* @param topResource 父节点
* @param resources 所有的子节点
*/
public <X extends ExTreeNode> X buildTree(X topResource,
LinkedHashMap<String, X> resources) {
Iterator<Map.Entry<String, X>> iter = resources.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String, X> entry = iter.next();
if (entry.getValue().getParentId() != null && entry.getValue().getParentId().equals(topResource.getId())) {
topResource.addChild(entry.getValue());
}
}
List<X> children = topResource.getChildren();
if (children == null || children.size() < 1){
return topResource;
}
for (X re : children) {
buildTree(re, resources);
}
return topResource;
}
/**
* 向子节点集合中添加节点
* @param exTreeNode 节点
*/
public <X extends ExTreeNode> void addChild(X exTreeNode) {
if (null == children)
children = new ArrayList<X>();
children.add(exTreeNode);
}
/**
* 获取节点ID
*/
public String getId() {
return id;
}
/**
* 设置节点ID
* @param id 节点ID
*/
public void setId(String id) {
this.id = id;
}
/**
* 获取父节点ID
*/
public String getParentId() {
return parentId;
}
/**
* 设置父节点ID
* @param parentId 父节点ID
*/
public void setParentId(String parentId) {
this.parentId = parentId;
}
/**
* 获取节点名称
*/
public String getName() {
return name;
}
/**
* 设置节点名称
* @param name 节点名称
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取子节点集合
*/
public <X> List<X> getChildren() {
return children;
}
/**
* 设置子节点集合
* @param children 子节点集合
*/
public <X extends ExTreeNode> void setChildren(List<X> children) {
this.children = children;
}
}
package com.app.framework.core.support.view.tree;
import java.io.Serializable;
/**
* ZTree基类
*/
public class ZTreeNode extends ExTreeNode implements Serializable{
private static final long serialVersionUID = 1L;
/**数据库中实例对象id主键*/
private String oid;
/**节点图标样式*/
private String iconCls;
/**是否父节点(为使用zTree而加,功能同leaf,与之相反)(true:父节点,false:子节点)*/
private Boolean isParent = false;
/**是否展开*/
private Boolean open;
/**节点是否选中*/
private Boolean checked;
/**节点是否可选(为使用zTree而加)(true:不显示复选框,false:显示复选框)*/
private Boolean nocheck;
/**扩展数据*/
private String extData;
/**
* 获取是否展开
*/
public Boolean getOpen() {
return open;
}
/**
* 设置是否展开
* @param open 是否展开
*/
public void setOpen(Boolean open) {
this.open = open;
}
/**
* 获取节点的选择状态
*/
public Boolean getChecked() {
return checked;
}
/**
* 设置节点的选择状态
* @param checked 节点的选择状态
*/
public void setChecked(Boolean checked) {
this.checked = checked;
}
/**
* 获取节点图标样式
*/
public String getIconCls() {
return iconCls;
}
/**
* 设置节点图标样式
* @param iconCls 图标样式
*/
public void setIconCls(String iconCls) {
this.iconCls = iconCls;
}
/**
* 获取是否是父节点
*/
public Boolean getIsParent() {
if(isParent == null){
isParent = false;
}
return isParent;
}
/**
* 设置是否是父节点
* @param isParent 是否是父节点
*/
public void setIsParent(Boolean isParent) {
this.isParent = isParent;
}
public String getOid() {
return oid;
}
public void setOid(String oid) {
this.oid = oid;
}
public Boolean getNocheck() {
return nocheck;
}
public void setNocheck(Boolean nocheck) {
this.nocheck = nocheck;
}
public String getExtData() {
return extData;
}
public void setExtData(String extData) {
this.extData = extData;
}
}
package com.app.framework.core.utils.db;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import java.sql.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 数据库工具类
*/
public class DBUtil {
private SqlSession session;
private Connection conn = null;
private PreparedStatement ps = null;
private ResultSet rs = null;
private String driver = "com.mysql.jdbc.Driver";
private String url;
private String username;
private String password;
public DBUtil(SqlSessionFactory sqlSessionFactory) {
session = SqlSessionUtils.getSqlSession(sqlSessionFactory);
}
public DBUtil(String url, String username, String password) {
this.url = url;
this.username = username;
this.password = password;
}
public DBUtil(String driver, String url, String username, String password) {
this.driver = driver;
this.url = url;
this.username = username;
this.password = password;
}
public SqlSession getSqlSession() {
return this.session;
}
public Connection getConnection() throws Exception {
if (conn == null || conn.isClosed()) {
if (this.session != null) {
conn = this.session.getConnection();
} else if (StringUtils.isNotBlank(url) && StringUtils.isNotBlank(username) && StringUtils.isNotBlank(password)) {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
}
}
return conn;
}
/**
* 根据SQL更新
*
* @param sql SQL语句
* @param params 参数数组
* @return 更新行数
*/
public int executeUpdate(String sql, Object[] params) {
int rows = 0;
try {
conn = this.getConnection();
ps = conn.prepareStatement(sql);
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
}
rows = ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
this.close();
}
return rows;
}
/**
* 根据SQL查询
*
* @param sql SQL语句
* @return List<Map < 字段名, 值>>
*/
public List<Map<String, String>> executeQuery(String sql) {
return this.executeQuery(sql, null);
}
/**
* 根据SQL查询
*
* @param sql SQL语句
* @param params 参数数组
* @return List<Map < 字段名, 值>>
*/
public List<Map<String, String>> executeQuery(String sql, Object[] params) {
List<Map<String, String>> list = new ArrayList<>();
try {
conn = this.getConnection();
ps = conn.prepareStatement(sql);
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while (rs.next()) {
Map<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < columnCount; i++) {
int index = i + 1;
map.put(rsmd.getColumnName(index).toLowerCase(), rs.getString(index));
}
list.add(map);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
this.close();
}
return list;
}
public void close() {
try {
if (rs != null) rs.close();
if (ps != null) ps.close();
if (conn != null) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
package com.app.framework.core.utils.file;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.RandomUtil;
import com.app.framework.core.exception.ValidException;
import com.app.framework.core.utils.request.RequestUtil;
import lombok.Data;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
/**
* 上传文件工具类
*/
public class UploadUtil {
private static final Logger log = LoggerFactory.getLogger(UploadUtil.class);
private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");
/**
* 上传路径
*/
private static String uploadPath;
/**
* 访问地址的baseUrl
*/
private static String baseUrl;
/**
* 根目录名称
* 默认uploadfiles
*/
private static String rootDirName;
public static void init(String uploadPath, String baseUrl) {
if (UploadUtil.uploadPath == null || !UploadUtil.uploadPath.equals(uploadPath)) {
UploadUtil.uploadPath = uploadPath;
}
if (UploadUtil.baseUrl == null || !UploadUtil.baseUrl.equals(baseUrl)) {
UploadUtil.baseUrl = baseUrl;
}
}
public static String getBaseUrl(HttpServletRequest request) {
if (StringUtils.isBlank(baseUrl)) {
baseUrl = RequestUtil.getBasePath(request);
}
return baseUrl;
}
public static String getRootDirName() {
if (StringUtils.isBlank(rootDirName)) {
if (StringUtils.isBlank(uploadPath) || "/".equals(uploadPath)) {//上传到项目根目录
rootDirName = "/uploadfiles";
} else {
rootDirName = uploadPath.substring(uploadPath.lastIndexOf("/"));
}
}
return rootDirName;
}
public static String getUploadPath(String savePath) {
if (StringUtils.isBlank(savePath)) {
savePath = DATE_FORMAT.format(new Date());
}
if (!savePath.startsWith("/")) {
savePath = new StringBuilder().append("/").append(savePath).toString();
}
StringBuilder builder = new StringBuilder();
if (StringUtils.isBlank(uploadPath)) {
builder.append(getRootDirName()).append(savePath);
} else {
builder.append(uploadPath).append(savePath);
}
return builder.toString();
}
public static String getBaseUrl(HttpServletRequest request, String savePath) {
if (StringUtils.isBlank(savePath)) {
savePath = DATE_FORMAT.format(new Date());
}
if (!savePath.startsWith("/")) {
savePath = new StringBuilder().append("/").append(savePath).toString();
}
String baseUrl = getBaseUrl(request);
StringBuilder url = new StringBuilder(baseUrl);
if (!baseUrl.endsWith(getRootDirName())) {
url.append(getRootDirName());
}
url.append(savePath);
return url.toString();
}
public static String upload(MultipartHttpServletRequest multipartRequest, UploadConfig uploadConfig) throws Exception {
init(uploadConfig.getUploadPath(), uploadConfig.getBaseUrl());
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
MultipartFile multipartFile = fileMap.values().iterator().next();
if (multipartFile == null) {
throw new ValidException("请选择文件");
}
long size = multipartFile.getSize();
if(uploadConfig.getFileSingleSizeLimit() > 0 && size > uploadConfig.getFileSingleSizeLimit()){//单个文件大小超过限制
throw new ValidException("文件大小超过限制");
}
String contentType = multipartFile.getContentType();
String ext = FileUtil.getSuffix(multipartFile.getOriginalFilename());
log.info("文件长度: " + size);
log.info("文件类型: " + contentType);
log.info("文件扩展名: " + ext);
log.info("文件原名: " + multipartFile.getOriginalFilename());
String fileName = new StringBuilder().append(System.nanoTime()).append(RandomUtil.randomString(6)).append(".").append(ext).toString();
File file = new File(getUploadPath(null));
if (!file.exists()) {
file.mkdirs();
log.info("创建文件路径: " + file.getAbsolutePath());
}
File createFile = new File(getUploadPath(null), fileName);
//处理压缩
if (uploadConfig != null && uploadConfig.isCompress() && size > uploadConfig.getCompressSize()) {
//判断是否压缩gif图片
if (ext.equalsIgnoreCase("gif") && !uploadConfig.isCompressGif()) {//不压缩gif图片
FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), createFile);
} else {
BufferedImage oldImage = ImageIO.read(multipartFile.getInputStream());
if (uploadConfig.getCompressScale() > 0) {
Image scale = ImgUtil.scale(oldImage, uploadConfig.getCompressScale());
ImgUtil.write(scale, createFile);
} else if (uploadConfig.getCompressWidth() > 0 && uploadConfig.getCompressHeight() > 0) {
Image scale = ImgUtil.scale(oldImage, uploadConfig.getCompressWidth(), uploadConfig.getCompressHeight());
ImgUtil.write(scale, createFile);
} else {
Image scale = ImgUtil.scale(oldImage, 1);
ImgUtil.write(scale, createFile);
}
}
} else {
FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), createFile);
}
log.info("创建成功: " + createFile.getAbsolutePath());
return getBaseUrl(multipartRequest, null) + "/" + fileName;
}
@Data
public static class UploadConfig implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 上传路径
*/
private String uploadPath;
/**
* 访问地址的baseUrl
*/
private String baseUrl;
/**
* 单个文件大小限制
*/
private long fileSingleSizeLimit;
/**
* 是否压缩
*/
private boolean compress;
/**
* 压缩后的宽
*/
private int compressWidth;
/**
* 压缩后的高
*/
private int compressHeight;
/**
* 压缩比例
*/
private float compressScale;
/**
* 如果图片大小小于此值,不再压缩,单位字节
*/
private long compressSize;
/**
* 是否压缩gif图片,默认false
*/
private boolean compressGif;
}
}
\ No newline at end of file
package com.app.framework.core.utils.number;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* 开闭区间工具类
*/
public class RangeUtil {
/**
* 开闭区间正则表达式
*/
private static final Pattern NUM_RANGE_PATTERN = Pattern.compile("[\\[|\\(]\\s?\\d+\\.?\\d*\\s?,\\s?\\d+\\.?\\d*\\s?[\\)|\\]]");
/**
* 左半区间正则表达式
*/
private static final Pattern LEFT_NUM_RANGE_PATTERN = Pattern.compile("[\\[|\\(]\\s?\\d+\\.?\\d*\\s?,\\s?[\\)|\\]]");
/**
* 右半区间正则表达式
*/
private static final Pattern RIGHT_NUM_RANGE_PATTERN = Pattern.compile("[\\[|\\(],\\s?\\d+\\.?\\d*\\s?[\\)|\\]]");
/**
* 判断是否为有效的数字区间范围
* @param numRange 数字区间,支持小数,左右皆允许为空,eg:(0, 2] or [1, 4] or [100, ]
* @return boolean
*/
public static boolean isValidNumRange(String numRange) {
return NUM_RANGE_PATTERN.matcher(numRange).matches()
|| LEFT_NUM_RANGE_PATTERN.matcher(numRange).matches()
|| RIGHT_NUM_RANGE_PATTERN.matcher(numRange).matches();
}
/**
* 判断数值是否在区间范围内
* @param number 数值
* @param numRange 开闭区间,支持小数,左右皆允许为空,eg:(0, 2] or [1, 4] or [100, ]
* @return boolean
*/
public static boolean inNumRange(BigDecimal number, String numRange) {
Objects.requireNonNull(numRange);
if (!isValidNumRange(numRange)) {
return false;
}
String[] pairs = numRange.split(",");
// 获取开闭区间的最小值和最大值
List<String> rangeNums = Arrays.stream(pairs).map(str -> str.replaceAll("[(|)|\\[|\\]]", "").trim()).collect(Collectors.toList());
BigDecimal minValue = "".equals(rangeNums.get(0)) ? null : new BigDecimal(rangeNums.get(0));
BigDecimal maxValue = "".equals(rangeNums.get(1)) ? null : new BigDecimal(rangeNums.get(1));
// 判定数值是否大于最小值
boolean minMatched = (minValue == null) || (pairs[0].startsWith("[") ? number.compareTo(minValue) >= 0 : number.compareTo(minValue) > 0);
// 判定数值是否小于最大值
boolean maxMatched = (maxValue == null) || (pairs[1].endsWith("]") ? number.compareTo(maxValue) <= 0 : number.compareTo(maxValue) < 0);
return minMatched && maxMatched;
}
public static void main(String[] args) {
// System.out.println(inNumRange(1, "(0, 2]"));
// System.out.println(inNumRange(1, "(, 2]"));
// System.out.println(inNumRange(1, "(1, 4]"));
// System.out.println(inNumRange(1, "(0, ]"));
// System.out.println();
// System.out.println(inNumRange(190, "[100, 400]"));
// System.out.println(inNumRange(BigDecimal.valueOf(300), "[100, 400)"));
System.out.println(inNumRange(BigDecimal.valueOf(800.89), "[0, )"));
}
}
package com.app.framework.core.utils.pwd;
import cn.hutool.crypto.SecureUtil;
import org.apache.commons.lang.StringUtils;
/**
* 密码工具类
*
*/
public class PasswordUtil {
/**
* 密码加密处理
*
* @param md5_password
* 标准md5加密后的密码
* @return 处理后的密码
*/
public static String encrypt(String md5_password) {
return SecureUtil.md5(md5_password + "_" + md5_password);
}
/**
* 判断密码是否与数据库中的密码一致
* @param md5_password 标准md5加密后的密码(用户输入的)
* @param db_password 数据库中存储的密码
* @return true:相等 false:不相等
*/
public static boolean equalsPwd(String md5_password, String db_password) {
if (StringUtils.equals(encrypt(md5_password), db_password)) {
return true;
} else {
return false;
}
}
/**
* 支付密码加密处理
*
* @param md5_password
* 标准md5加密后的密码
* @return 处理后的密码
*/
public static String paypwd_encrypt(String md5_password) {
return SecureUtil.md5(md5_password + "$" + md5_password);
}
/**
* 支付密码
* 判断密码是否与数据库中的密码一致
* @param md5_password 标准md5加密后的密码(用户输入的)
* @param db_password 数据库中存储的密码
* @return true:相等 false:不相等
*/
public static boolean paypwd_equalsPwd(String md5_password, String db_password) {
if (StringUtils.equals(paypwd_encrypt(md5_password), db_password)) {
return true;
} else {
return false;
}
}
}
package com.app.framework.core.utils.request;
import org.apache.commons.lang.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
/**
* Request工具类
*/
public class RequestUtil {
public static final String REQUEST_AJAX_HEADER = "X-Requested-With";
public static final String XML_HTTP_REQUEST = "XMLHttpRequest";
private static String RequestServer = null;
/**
* SpringMvc下获取request
*/
public static HttpServletRequest getRequest() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
/**
* 获取BasePath
*
* @return request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath();
*/
public static String getBasePath(HttpServletRequest request) {
if (RequestServer == null) {
String port = request.getServerPort() + "";
port = "80".equals(port) ? "" : (":" + port);
String requestServer = request.getScheme() + "://" + request.getServerName() + port;
RequestServer = requestServer + request.getContextPath();
}
return RequestServer;
}
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String Xip = request.getHeader("X-Real-IP");
String XFor = request.getHeader("X-Forwarded-For");
if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
//多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = XFor.indexOf(",");
if (index != -1) {
return XFor.substring(0, index);
} else {
return XFor;
}
}
XFor = Xip;
if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
return XFor;
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor)) {
XFor = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(XFor) ? "127.0.0.1" : XFor;
}
/**
* 判断是否是Ajax请求
*
* @param request 请求
* @return true or false
*/
public static boolean isAjaxRequest(HttpServletRequest request) {
return request.getHeader(REQUEST_AJAX_HEADER) != null && request.getHeader(REQUEST_AJAX_HEADER).equalsIgnoreCase(XML_HTTP_REQUEST);
}
}
package com.app.framework.core.utils.request;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* Session工具类
*/
public class SessionUtil {
/**
* 登录会话名称
*/
public static final String OPERATOR_CONTEXT = "operator_context";
/**
* 将数据存放到session中
*
* @param request
* @param name 名称
* @param o 数据
*/
public static void set(HttpServletRequest request, String name, Object o) {
if (request != null && name != null && o != null) {
request.getSession().setAttribute(name, o);
}
}
/**
* 获取session中的数据
*
* @param request
*/
public static <T> T get(HttpServletRequest request, String name) {
if (request == null || name == null) return null;
try {
HttpSession session = request.getSession();
if (session == null) return null;
Object o = session.getAttribute(name);
if (o == null) return null;
return (T) o;
} catch (Exception e) {
}
return null;
}
/**
* 从session中移除数据
*/
public static void remove(HttpServletRequest request, String name) {
HttpSession session = request.getSession();
if (session != null && name != null) {
session.removeAttribute(name);
}
}
/**
* 将当前用户存放到session中
*
* @param request
* @param loginUser
*/
public static <T> void setCurrentUser(HttpServletRequest request, T loginUser) {
set(request, OPERATOR_CONTEXT, loginUser);
}
/**
* 获取当前登录的用户
*
* @param request
*/
public static <T> T getCurrentUser(HttpServletRequest request) {
return get(request, OPERATOR_CONTEXT);
}
/**
* 从session中移除当前用户
*/
public static void removeCurrentUser(HttpServletRequest request) {
remove(request, OPERATOR_CONTEXT);
}
}
package com.app.framework.core.web.captcha;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.img.ImgUtil;
import com.app.framework.core.utils.request.SessionUtil;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import javax.servlet.Servlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
/**
* 图形验证码工具类
*
* 图形验证码用法:在全局配置中注册,如下:
*
* @Bean
* public ServletRegistrationBean captchaServletRegistration() {
* ServletRegistrationBean registration = new ServletRegistrationBean(CaptchaUtils.buildServlet());
* registration.addUrlMappings("/web/captcha.jpg");
* return registration;
* }
*
* 前端用法:
* <img src="${contextPath}/web/captcha.jpg" width="92" height="40" alt="点击刷新验证码"
* onclick="$(this).attr('src','${contextPath}/web/captcha.jpg?timestamp='+new Date());">
*
* 后端输入验证:
* CaptchaUtil.check(request, code);
*
*/
public class CaptchaUtil {
private static final String SESSION_NAME = "CaptchaCode";
private static final int WIDTH = 100;//生成的图片的宽度
private static final int HEIGHT = 40;//生成的图片的高度
/**
* 创建图形验证码Servlet
* @return Servlet
*/
public static Servlet buildServlet() {
return buildServlet(WIDTH, HEIGHT);
}
/**
* 创建图形验证码Servlet
* @return Servlet
*/
public static Servlet buildServlet(int width, int height) {
return new HttpServlet() {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg");
String codeLength = request.getParameter("codeLength");
if(StringUtils.isBlank(codeLength))codeLength = "4";
// 产生验证码
String code = new RandomGenerator(Integer.parseInt(codeLength)).generate();
// 将验证码存储起来,便于用户输入之后的验证
SessionUtil.set(request, SESSION_NAME, code);
// 生成图形验证码
//CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(width, height);
LineCaptcha captcha = cn.hutool.captcha.CaptchaUtil.createLineCaptcha(width, height);
Image image = captcha.createImage(code);
ImgUtil.writeJpg(image, response.getOutputStream());
}
};
}
/**
* 校验用户输入的验证码是否正确
* @param request
* @param code 用户输入的验证码
* @return
*/
public static boolean check(HttpServletRequest request, String code) {
Object o = SessionUtil.get(request, SESSION_NAME);
boolean equals = ObjectUtils.equals(o, code);
if (equals) {
SessionUtil.remove(request, SESSION_NAME);
}
return equals;
}
}
package com.app.framework.core.web.filter;
import com.app.framework.core.utils.request.SessionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 前端接口身份认证拦截器
* 用于非前后端分离的项目,前端用户通过Session存储登录信息
* 默认所有资源都是开放的,只对受保护的资源进行登录认证,受保护的URL要求包含: /authc/
* 根据Session中的会话信息,验证用户是否登录,以及是否有权限访问当前URL
*
*/
public class WebHttpServletRequestFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(WebHttpServletRequestFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) srequest;
HttpServletResponse response = (HttpServletResponse)sresponse;
String uri = request.getRequestURI();
// logger.info(String.format("前端身份认证[URI = %s]:", uri));
if (uri.indexOf("/authc/") > -1) {//需要登录才能访问的资源,验证是否登录
if (SessionUtil.getCurrentUser(request) == null) {//未登录,跳转到登录页面
request.setAttribute("redirectUrl", uri);
request.getRequestDispatcher("/web/login").forward(srequest, sresponse);
// response.sendRedirect(request.getContextPath() + "/web/login");
} else {
chain.doFilter(srequest, sresponse);
}
} else if (uri.indexOf("/api/") > -1) {
chain.doFilter(srequest, sresponse);
} else if (uri.indexOf("/web/") > -1) {
chain.doFilter(srequest, sresponse);
} else {
response.sendRedirect("/404");
}
}
@Override
public void destroy() {
}
}
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