Commit fb0b2416 authored by 侯力峰's avatar 侯力峰
Browse files

首次开源发布

parent f978a999
Pipeline #2758 canceled with stages
package cn.spatiotemporal.web.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* 采用逻辑删除的实体类的基类
* @author marquis
*
*/
@Data
@EqualsAndHashCode(callSuper=true)
@ToString(callSuper=true)
public class LogicDeleteEntity extends BaseEntity {
/**
*
*/
private static final long serialVersionUID = 286976278233286267L;
/**
* 逻辑删除标记
*/
@TableField("is_deleted")
@TableLogic
private Integer isDeleted;
}
package cn.spatiotemporal.web.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* 乐观锁实体类的基类,实现基于乐观锁的并发控制
* @author marquis
*
* @param <ID>
*/
@Data
@EqualsAndHashCode(callSuper=true)
@ToString(callSuper=true)
public class OptimisticLockerEntity extends BaseEntity {
private static final long serialVersionUID = 5699123159318695750L;
/**
* 版本(用于乐观锁并发控制策略)
*/
@TableField("version")
@Version
private Integer version;
}
package cn.spatiotemporal.web.core.domain.entity.admin;
import java.io.Serializable;
import org.springframework.security.core.GrantedAuthority;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 访问权限(包括菜单和按钮两种类型)
* @author marquis
*
*/
@AllArgsConstructor
@Data
public class Authority implements GrantedAuthority, Serializable {
/**
*
*/
private static final long serialVersionUID = 2368424813767914830L;
private String authority;
private Integer type;
}
package cn.spatiotemporal.web.core.domain.entity.admin;
import java.io.Serializable;
import java.util.List;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import cn.spatiotemporal.web.core.domain.entity.CommonEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* 操作日志表
*
* @author wenxuan.hu
* @since 2021-01-20
*/
@TableName("admin_operation_log")
@Data
@EqualsAndHashCode(callSuper=false)
@ToString(callSuper=true)
public class OperationLog extends CommonEntity implements Serializable {
private static final long serialVersionUID = 1L;
@TableField("operator_id")
private String operatorId;
@TableField("operator_name")
private String operatorName;
/**
* 用户操作
*/
@TableField("operation")
private String operation;
/**
* 响应时间
*/
@TableField("response_time")
private Integer responseTime;
/**
* 请求方法
*/
@TableField("method")
private String method;
/**
* 请求参数
*/
@TableField("params")
private String params;
/**
* 状态:Success成功 Fail失败
*/
@TableField("status")
private String status;
/**
* 错误信息
*/
@TableField("error_msg")
private String errorMsg;
/**
* IP地址
*/
@TableField("log_ip")
private String logIp;
}
package cn.spatiotemporal.web.core.domain.entity.admin;
import java.io.Serializable;
import java.util.List;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import cn.spatiotemporal.web.core.domain.entity.CommonEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* 系统服务日志表
*
* @author wenxuan.hu
* @since 2021-01-20
*/
@TableName("admin_service_log")
@Data
@EqualsAndHashCode(callSuper=false)
@ToString(callSuper=true)
public class ServiceLog extends CommonEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 模块ID
*/
@TableField("module_id")
private String moduleId;
/**
* 类名称
*/
@TableField("class_name")
private String className;
/**
* 用户操作
*/
@TableField("service")
private String service;
/**
* 响应时间
*/
@TableField("response_time")
private Integer responseTime;
/**
* 请求方法
*/
@TableField("method")
private String method;
/**
* 请求参数
*/
@TableField("params")
private String params;
/**
* 状态:Success成功 Fail失败
*/
@TableField("status")
private String status;
/**
* 错误信息
*/
@TableField("error_msg")
private String errorMsg;
/**
* IP地址
*/
@TableField("log_ip")
private String logIp;
}
package cn.spatiotemporal.web.core.domain.entity.admin;
import java.io.Serializable;
import java.util.List;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.userdetails.UserDetails;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import cn.spatiotemporal.web.core.domain.entity.CommonEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@TableName("admin_user")
@Data
@EqualsAndHashCode(callSuper=false)
@ToString(callSuper=true)
public class User extends CommonEntity implements Serializable, UserDetails, CredentialsContainer {
private static final long serialVersionUID = 2114355975229097429L;
/**
* 成员
*/
private Long memberId;
private String username;
private String password;
private String salt;
@TableField(exist = false)
private String accessToken;
@JsonSerialize(using = ToStringSerializer.class)
private Long orgId;
@TableField("is_enabled")
private boolean enabled;
private transient List<String> roles;
private transient List<Authority> authorities;
private transient List<String> permissions;
private String realName;
@Override
public boolean isAccountNonExpired() {
// 账号永不过期
return true;
}
@Override
public boolean isAccountNonLocked() {
// 与账号可用状态相同
return isEnabled();
}
@Override
public boolean isCredentialsNonExpired() {
// 密码永不过期
return true;
}
@Override
public void eraseCredentials() {
// TODO 未完成
};
}
package cn.spatiotemporal.web.core.domain.vo;
import java.io.Serializable;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(description= "REST查询条件")
@Data
public class RequestVO<T> implements Serializable {
/**
*
*/
private static final long serialVersionUID = -830863935742261168L;
@ApiModelProperty(value = "每页大小(行数)")
private Long size;
@ApiModelProperty(value = "当前页码")
private Long current;
@ApiModelProperty(value = "查询条件")
private T condition;
@ApiModelProperty(value = "排序")
private String order;
public RequestVO() {
}
public RequestVO(T obj) {
this.condition = obj;
}
public RequestVO(Long size, Long current, T obj) {
this.size = size;
this.current = current;
this.condition = obj;
}
public RequestVO(Long size, Long current, T obj, String order) {
this.size = size;
this.current = current;
this.condition = obj;
this.order = order;
}
}
package cn.spatiotemporal.web.core.domain.vo;
import java.util.HashMap;
import java.util.Map;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
public class ReturnMap extends ReturnVO<Map<String, Object>> {
/**
*
*/
private static final long serialVersionUID = 5440131552722554584L;
public ReturnMap() {
super(new HashMap<String, Object>());
}
public ReturnMap(ReturnEnum returnEnum) {
super(returnEnum, new HashMap<String, Object>());
}
public void put(String key, Object data) {
((Map<String, Object>) this.getData()).put(key, data);
}
}
package cn.spatiotemporal.web.core.domain.vo;
import java.io.Serializable;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel(description= "REST返回数据")
@Data
public class ReturnVO<T> implements Serializable {
/**
*
*/
private static final long serialVersionUID = 221173669518504486L;
@ApiModelProperty(value = "执行状态码")
private String code;
@ApiModelProperty(value = "返回消息")
private String msg;
@ApiModelProperty(value = "返回数据")
private Object data;
public ReturnVO() {
this.code = ReturnEnum.SUCCESS.getCode();
this.msg = ReturnEnum.SUCCESS.getMessage();
}
public ReturnVO(T obj) {
this.code = ReturnEnum.SUCCESS.getCode();
this.msg = ReturnEnum.SUCCESS.getMessage();
this.data = obj;
}
public ReturnVO(ReturnEnum returnEnum) {
this.code = returnEnum.getCode();
this.msg = returnEnum.getMessage();
}
public ReturnVO(ReturnEnum returnEnum, T obj) {
this.code = returnEnum.getCode();
this.msg = returnEnum.getMessage();
this.data = obj;
}
public ReturnVO(String code, String message) {
this.code = code;
this.msg = message;
}
public ReturnVO(String code, String message, T obj) {
this.code = code;
this.msg = message;
this.data = obj;
}
}
package cn.spatiotemporal.web.core.exception;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
/**
* 业务异常类的公共基类
* @author marquis
*
*/
public class BaseBusinessException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 4534112171112827815L;
private String code;
public BaseBusinessException(ReturnEnum returnEnum) {
super(returnEnum.getMessage());
this.code = returnEnum.getCode();
}
public BaseBusinessException(String code, String message) {
super(message);
this.code = code;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
package cn.spatiotemporal.web.core.exception.handler;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import cn.spatiotemporal.web.core.domain.vo.ReturnVO;
import cn.spatiotemporal.web.core.exception.BaseBusinessException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 未知异常处理
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ReturnVO<Void> exceptionHandler(Exception e) {
log.error(ReturnEnum.FAILED.getMessage(), e);
return new ReturnVO<Void>(ReturnEnum.FAILED.getCode(), e.getMessage());
}
@ExceptionHandler(value = BaseBusinessException.class)
@ResponseBody
public ReturnVO<Void> businessExceptionHandler(BaseBusinessException e) {
log.error(e.getMessage(), e);
return new ReturnVO<Void>(e.getCode(), e.getMessage());
}
/**
*
* @Title: handlerMaxUploadFile
* @Description: 捕获异常:MaxUploadSizeExceededException
* @param ex
* @return
* ReturnVO<Void>
*/
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ReturnVO<Void> handlerMaxUploadFile(MaxUploadSizeExceededException ex) {
String msg = "文件上传大小不能超过4MB!";
log.warn(msg);
return new ReturnVO<Void>("400", msg);
}
}
package cn.spatiotemporal.web.core.permission;
import java.lang.reflect.Method;
import java.util.List;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import cn.spatiotemporal.web.core.domain.entity.admin.Authority;
import cn.spatiotemporal.web.core.domain.entity.admin.User;
import cn.spatiotemporal.web.core.exception.BaseBusinessException;
import lombok.extern.slf4j.Slf4j;
@Aspect
@Component
@Slf4j
public class PermissionAspect {
@Pointcut("execution( * cn.spatiotemporal.web..*controller..*Controller*.*(..))")
public void pointCut() {
}
@Around("pointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
PermissionSource ps = method.getAnnotation(PermissionSource.class);
if(ps!=null) {
log.info(ps.code());
String psCode = ps.code();
if (psCode.contains(".")) {
psCode = psCode.substring(0, psCode.indexOf("."));
}
//如果方法上Log注解不为空,则执行proceed()
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if(auth==null || auth.getPrincipal() instanceof String) {
throw new BaseBusinessException(ReturnEnum.ERROR_NO_AUTHORITY);
}
User userDetails =(User) auth.getPrincipal();
List <String> authList = userDetails.getPermissions();
if(!authList.contains(psCode) && !authList.contains(ps.code())) {
throw new BaseBusinessException(ReturnEnum.ERROR_PERMISSION_DENIED);
}
}
return joinPoint.proceed();
}
}
package cn.spatiotemporal.web.core.permission;
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;
import cn.spatiotemporal.web.core.constants.enums.PermissionType;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermissionSource {
public String code() default "";
public String name() default "";
public PermissionType permType() default PermissionType.MENU;
}
package cn.spatiotemporal.web.core.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import cn.spatiotemporal.web.core.domain.vo.ReturnVO;
/**
* 实现AccessDeniedHandler接口,处理无权限访问的情况
*
* @author marquis
*
*/
@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e)
throws IOException, ServletException {
response.getWriter().write(JSON.toJSONString(new ReturnVO<Void>(ReturnEnum.ERROR_PERMISSION_DENIED)));
}
}
package cn.spatiotemporal.web.core.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import cn.spatiotemporal.web.core.domain.vo.ReturnVO;
/**
* 实现AuthenticationEntryPoint接口,处理用户未登录
*
* @author marquis
*
*/
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
throws IOException, ServletException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/javascript;charset=utf-8");
response.getWriter().write(JSON.toJSONString(new ReturnVO<Void>(ReturnEnum.ERROR_NO_AUTHORITY)));
}
}
package cn.spatiotemporal.web.core.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import cn.spatiotemporal.web.core.domain.vo.ReturnVO;
/**
* 实现AuthenticationFailureHandler接口,处理用户登录失败
* @author marquis
*
*/
@Component
public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
response.setCharacterEncoding("utf-8");
response.setContentType("text/javascript;charset=utf-8");
String failed= new String(JSON.toJSONString(new ReturnVO<Void>(ReturnEnum.ERROR_ACCOUNT_OR_PASSWORD)).getBytes(),"UTF-8");
response.getWriter().write(failed);
}
}
package cn.spatiotemporal.web.core.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import cn.spatiotemporal.web.core.constants.enums.ReturnEnum;
import cn.spatiotemporal.web.core.domain.vo.ReturnVO;
/**
* 实现LogoutSuccessHandler接口,处理退出成功
* @author marquis
*
*/
@Component
public class RestLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
//清除token
//返回客户端结果信息
response.getWriter().write(JSON.toJSONString(new ReturnVO<Void>(ReturnEnum.SUCCESS)));
}
}
package cn.spatiotemporal.web.core.service;
import cn.spatiotemporal.web.core.domain.entity.admin.OperationLog;
/**
* 操作日志表 服务类
*
* @author wenxuan.hu
* @since 2021-01-20
*/
public interface IOperationLogService {
void save(OperationLog userLog);
}
package cn.spatiotemporal.web.core.service;
import cn.spatiotemporal.web.core.domain.entity.admin.ServiceLog;
/**
* 系统服务日志表 服务类
*
* @author wenxuan.hu
* @since 2021-01-20
*/
public interface IServiceLogService {
void save(ServiceLog sysLog);
}
package cn.spatiotemporal.web.core.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Service;
import cn.spatiotemporal.web.core.annotation.DisableSysLog;
import cn.spatiotemporal.web.core.dao.OperationLogDao;
import cn.spatiotemporal.web.core.domain.entity.admin.OperationLog;
import cn.spatiotemporal.web.core.service.IOperationLogService;
@Service
@ConditionalOnMissingBean(annotation = DisableSysLog.class)
public class OperationLogServiceImpl implements IOperationLogService {
@Autowired
private OperationLogDao dao;
@Override
public void save(OperationLog userLog) {
dao.insert(userLog);
}
}
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