Commit 4961db29 authored by 赵啸非's avatar 赵啸非

Initial commit

parents
Pipeline #2931 canceled with stages
.deploy_git/
node_modules/
public/
target/
.idea/
*.iml
dist/
\ No newline at end of file
.deploy_git/
node_modules/
public/
target/
.idea/
\ No newline at end of file
-- ----------------------------
-- 应用访问记录
-- ----------------------------
DROP TABLE IF EXISTS `mortals_xhx_app_record`;
CREATE TABLE `mortals_xhx_app_record`
(
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`app_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标题',
`app_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '封面',
`query` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '询问内容',
`access_time` datetime DEFAULT NULL COMMENT '访问时间',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注',
`create_user_id` bigint(20) DEFAULT NULL COMMENT '创建用户',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_general_ci
ROW_FORMAT = DYNAMIC COMMENT ='应用访问记录';
This diff is collapsed.
This diff is collapsed.
#!/bin/sh
RETVAL=$?
SHELL_NAME="deploy"
BASEDIR=$(dirname $0)
BASEDIR=$( (
cd "$BASEDIR"
pwd
))
LOCK_FILE="/tmp/deploy.lock"
# 时间变量
CDATE=$(date "+%Y-%m-%d")
CTIME=$(date "+%H:%M:%S")
SHELL_LOG="${BASEDIR}/${SHELL_NAME}.log"
JAVA_HOME="/usr/local/java/jdk1.8"
SERVICE_PATH="/usr/lib/systemd/system"
PUBLISH_PATH="/home/publish"
PROJECT_NAME="@project.artifactId@"
PROJECT_EXECPATH="${PUBLISH_PATH}/${PROJECT_NAME}"
PROJECT_UI_EXECPATH="${PUBLISH_PATH}/${PROJECT_NAME}-ui/dist"
PROJECT_FILENAME="${PROJECT_NAME}.tar.gz"
PROJECT_UI_FILENAME="${PROJECT_NAME}-ui.tar.gz"
PROJECT_SERVICE="${SERVICE_PATH}/${PROJECT_NAME}.service"
#写日志
writelog() {
LOGINFO=$1
echo "${CDATE} ${CTIME}: ${SHELL_NAME} : ${LOGINFO}" >>${SHELL_LOG}
echo ${LOGINFO}
}
#清理目标
clear_deploy() {
SERVICE=$1
EXECPATH=$2
#清理后台自启服务
rm -f ${SERVICE}
#清理执行文件目录
rm -rf ${EXECPATH}
}
#清理ui
clear_ui_deploy() {
EXEC_UI_PATH=$1
rm -rf ${EXEC_UI_PATH}
mkdir -p ${EXEC_UI_PATH}
}
build_service() {
SERVICE=$1
EXECPATH=$2
echo "" >${SERVICE}
echo "[Unit]" >>${SERVICE}
echo "Description=${PROJECT_NAME}" >>${SERVICE}
echo "After=network.target" >>${SERVICE}
echo "" >>${SERVICE}
echo "[Service]" >>${SERVICE}
echo "Environment=\"JAVA_HOME=$JAVA_HOME\"" >>${SERVICE}
echo "Type=forking" >>${SERVICE}
echo "ExecStart=${EXECPATH}/bin/start.sh" >>${SERVICE}
echo "ExecStop=${EXECPATH}/bin/shutdown.sh" >>${SERVICE}
echo "PrivateTmp=true" >>${SERVICE}
echo "" >>${SERVICE}
echo "[Install]" >>${SERVICE}
echo "WantedBy=multi-user.target" >>${SERVICE}
writelog "${PROJECT_NAME}服务创建完成!"
}
#启动服务与nginx
start_service() {
systemctl enable ${PROJECT_NAME}
systemctl daemon-reload
writelog "${PROJECT_NAME}服务启动..."
systemctl stop ${PROJECT_NAME} && systemctl start ${PROJECT_NAME}
project_status=$(systemctl status "${PROJECT_NAME}"|grep Active |awk '{print $2}')
jcpid=$(ps -ef | grep -v "grep" | grep "${PROJECT_NAME} " | awk '{print $2}')
writelog "${PROJECT_NAME}服务启动,PID is ${jcpid} ,status:${project_status}"
}
#部署后台服务
project_deploy() {
writelog "${PROJECT_NAME}_deploy"
systemctl stop ${PROJECT_NAME}
sleep 5
clear_deploy ${PROJECT_SERVICE} ${PROJECT_EXECPATH}
writelog "${PROJECT_NAME}_clear_finish"
tar -zvxf ./${PROJECT_FILENAME} -C ${PUBLISH_PATH}
build_service ${PROJECT_SERVICE} ${PROJECT_EXECPATH}
start_service
writelog "${PROJECT_NAME}_deploy_finish"
}
#部署前台服务
project_ui_deploy() {
writelog "${PROJECT_NAME}_ui_deploy"
clear_ui_deploy ${PROJECT_UI_EXECPATH}
tar -zvxf ./${PROJECT_UI_FILENAME} -C ${PUBLISH_PATH}
writelog "${PROJECT_NAME}_ui_deploy_finish"
}
#主函数
main() {
echo "后台服务部署"
project_deploy
exit ${RETVAL}
}
main $1
if not exist "%JAVA_HOME%\bin\jps.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better! & EXIT /B 1
setlocal
set "PATH=%JAVA_HOME%\bin;%PATH%"
echo killing server
for /f "tokens=1" %%i in ('jps -m ^| find "@project.artifactId@"') do ( taskkill /F /PID %%i )
echo Done!
#! /bin/sh
PORT="@profiles.server.port@"
BASEDIR=$(dirname $0)
BASEDIR=$( (
cd "$BASEDIR"
pwd
))
PROJECT_NAME="@project.artifactId@"
MAIN_CLASS="$PROJECT_NAME"
if [ ! -n "$PORT" ]; then
echo $"Usage: $0 {port}"
exit $FAIL
fi
pid=$(ps ax | grep -i "$MAIN_CLASS" | grep java | grep -v grep | awk '{print $1}')
if [ -z "$pid" ]; then
echo "No Server running."
exit 1
fi
echo "stoping application $PROJECT_NAME......"
kill -15 ${pid}
echo "Send shutdown request to Server $PROJECT_NAME OK"
echo off
if not exist "%JAVA_HOME%\bin\java.exe" echo Please set the JAVA_HOME variable in your environment, We need java(x64)! jdk8 or later is better! & EXIT /B 1
set "JAVA=%JAVA_HOME%\bin\java.exe"
set BASEDIR=%~dp0
set BASEDIR="%BASEDIR:~0,-5%"
set PROJECT_NAME=@project.artifactId@
set APP_NAME=%PROJECT_NAME%-@project.version@.jar
set LOG_PATH="%BASEDIR%@profiles.log.path@/%PROJECT_NAME%"
if not exist "%LOG_PATH%" md "%LOG_PATH%"
set GC_PATH=%LOG_PATH%/gc.log
set HS_ERR_PATH=%LOG_PATH%PORT%-hs_err.log
set HEAP_DUMP_PATH=%LOG_PATH%/heap_dump.hprof
set TEMP_PATH=%LOG_PATH%/temp/
if not exist "%TEMP_PATH%" md "%TEMP_PATH%"
rem jvm启动参数
set JAVA_OPTS=-Xms512M -Xmx512M -Xss256K -XX:+UseAdaptiveSizePolicy -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:GCTimeRatio=39 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError
set JAVA_OPTS=%JAVA_OPTS% -XX:+PrintGCDateStamps -Xloggc:%GC_PATH%
set JAVA_OPTS=%JAVA_OPTS% -XX:ErrorFile=%HS_ERR_PATH%
set JAVA_OPTS=%JAVA_OPTS% -XX:HeapDumpPath=%HEAP_DUMP_PATH%
rem jvm config
set JVM_CONFIG=%JVM_CONFIG% -Dapp.name=%PROJECT_NAME%
set JVM_CONFIG=%JVM_CONFIG% -Dapp.port=%PORT%
set JVM_CONFIG=%JVM_CONFIG% -Djava.io.tmpdir=%TEMP_PATH%
set JVM_CONFIG=%JVM_CONFIG% -Dbasedir=%BASEDIR%
set JVM_CONFIG=%JVM_CONFIG% -Dloader.path=file://%BASEDIR%/conf,file://%BASEDIR%/lib
set DEBUG_OPTS=
if ""%1"" == ""debug"" (
set DEBUG_OPTS= -Xloggc:../logs/gc.log -verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../logs
goto debug
)
set JMX_OPTS=
if ""%1"" == ""jmx"" (
set JMX_OPTS= -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9888 -Dcom.sun.management.jmxremote.ssl=FALSE -Dcom.sun.management.jmxremote.authenticate=FALSE
goto jmx
)
set "LOG_OPTS=--logging.config=%BASEDIR%/conf/logback-spring.xml"
echo "Starting the %APP_NAME%"
"%JAVA%" %JAVA_OPTS% -server %JVM_CONFIG% -jar %BASEDIR%/boot/%APP_NAME%
echo ""%JAVA%" %JAVA_OPTS% -server %JVM_CONFIG% -jar %BASEDIR%/boot/%APP_NAME% "
goto end
:debug
echo "debug"
"%JAVA%" -Xms512m -Xmx512m -server %DEBUG_OPTS% %JVM_CONFIG% -jar ../boot/%APP_NAME%
goto end
:jmx
"%JAVA%" -Xms512m -Xmx512m -server %JMX_OPTS% %JVM_CONFIG% -jar ../boot/%APP_NAME%
goto end
:end
pause
#!/bin/sh
PORT="@profiles.server.port@"
DEBUG=@profiles.server.debug@
BASEDIR=`dirname $0`/..
BASEDIR=`(cd "$BASEDIR"; pwd)`
PROJECT_NAME="@project.artifactId@";
MAIN_CLASS="$PROJECT_NAME-@project.version@.jar";
LOG_PATH="@profiles.log.path@/$PROJECT_NAME"
GC_PATH=$LOG_PATH/$PROJECT_NAME"-gc.log"
HS_ERR_PATH=$LOG_PATH/$PROJECT_NAME"-hs_err.log"
HEAP_DUMP_PATH=$LOG_PATH/$PROJECT_NAME"-heap_dump.hprof"
TEMP_PATH=$LOG_PATH/temp/
SUCCESS=0
FAIL=9
if [ ! -n "$PORT" ]; then
echo $"Usage: $0 {port}"
exit $FAIL
fi
if [ ! -d $LOG_PATH ];
then
mkdir -p $LOG_PATH;
fi
if [ ! -d $TEMP_PATH ];
then
mkdir -p $TEMP_PATH;
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD=`which java > /dev/null 2>&1`
echo "Error: JAVA_HOME is not defined correctly."
exit $ERR_NO_JAVA
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "We cannot execute $JAVACMD"
exit $ERR_NO_JAVA
fi
if [ -e "$BASEDIR" ]
then
JAVA_OPTS="-Xms1024M -Xmx2048M -Xss256K -XX:+UseAdaptiveSizePolicy -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:GCTimeRatio=39 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:$GC_PATH -XX:+HeapDumpOnOutOfMemoryError -XX:ErrorFile=$HS_ERR_PATH -XX:HeapDumpPath=$HEAP_DUMP_PATH"
fi
CLASSPATH=$CLASSPATH_PREFIX:
EXTRA_JVM_ARGUMENTS=""
cd "$BASEDIR/boot";
echo "starting application $PROJECT_NAME......"
exec "$JAVACMD" $JAVA_OPTS \
$EXTRA_JVM_ARGUMENTS \
$DEBUG \
-Dapp.name="$PROJECT_NAME" \
-Dapp.port="$PORT" \
-Dbasedir="$BASEDIR" \
-Djava.io.tmpdir=$TEMP_PATH \
-jar $MAIN_CLASS \
> /dev/null &
for i in {1..60}
do
jcpid=`ps -ef | grep -v "grep" | grep "$MAIN_CLASS" | grep "app.port=$PORT" | sed -n '1P' | awk '{print $2}'`
if [ $jcpid ]; then
echo "The $PROJECT_NAME start finished, PID is $jcpid"
exit $SUCCESS
else
echo "starting the application .. $i"
sleep 1
fi
done
echo "$PROJECT_NAME start failure!"
#! /bin/sh
PORT="@profiles.server.port@"
BASEDIR=`dirname $0`
BASEDIR=`(cd "$BASEDIR"; pwd)`
PROJECT_NAME="@project.artifactId@"
MAIN_CLASS="$PROJECT_NAME";
if [ ! -n "$PORT" ]; then
echo $"Usage: $0 {port}"
exit $FAIL
fi
echo "stoping application $PROJECT_NAME......"
jcpid=`ps -ef | grep -v "grep" | grep "$MAIN_CLASS" | grep "app.port=$PORT" | sed -n '1P' | awk '{print $2}'`
if [ -z $jcpid ]; then
echo "$PROJECT_NAME is not started or has been stopped!"
else
curl -X POST -i -u $SECURITY_USERNAME:$SECURITY_PASSWORD http://127.0.0.1:$PORT/xxx_manager/shutdown
for i in {1..60}
do
jcpid=`ps -ef | grep -v "grep" | grep "$MAIN_CLASS" | grep "app.port=$PORT" | sed -n '1P' | awk '{print $2}'`
if [ -z $jcpid ]; then
echo "$PROJECT_NAME has been stopped!"
break
else
echo "stoping the application .. $i"
sleep 1
fi
done
jcpid=`ps -ef | grep -v "grep" | grep "$MAIN_CLASS" | grep "app.port=$PORT" | sed -n '1P' | awk '{print $2}'`
if [ $jcpid ]; then
[ -z $jcpid ] || kill -15 $jcpid
for i in {1..30}
do
jcpid=`ps -ef | grep -v "grep" | grep "$MAIN_CLASS" | grep "app.port=$PORT" | sed -n '1P' | awk '{print $2}'`
if [ -z $jcpid ]; then
echo "$PROJECT_NAME has been stopped!"
break
else
echo "stoping the application .. $i"
sleep 1
fi
done
fi
jcpid=`ps -ef | grep -v "grep" | grep "$MAIN_CLASS" | grep "app.port=$PORT" | sed -n '1P' | awk '{print $2}'`
if [ $jcpid ]; then
[ -z $jcpid ] || kill -9 $jcpid
[ $? -eq 0 ] && echo "Stop $PROJECT_NAME OK!" || echo "Stop $PROJECT_NAME Fail!"
fi
fi
package com.mortals.xhx;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.impl.LocalCacheServiceImpl;
import com.mortals.framework.springcloud.boot.BaseWebApplication;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication(scanBasePackages = {"com.mortals"})
@ServletComponentScan("com.mortals")
@ImportResource(locations = {"classpath:config/spring-config.xml"})
public class ManagerApplication extends BaseWebApplication {
@Bean
public ICacheService cacheService() {
return new LocalCacheServiceImpl();
}
public static void main(String[] args) {
SpringApplication.run(ManagerApplication.class, args);
}
}
package com.mortals.xhx.base.framework;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.springframework.util.ObjectUtils;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 自定义日期反序列化
* @author: zxfei
* @date: 2022/6/30 10:49
* @description:
**/
public class CustomJsonDateDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date = jp.getText();
if (!ObjectUtils.isEmpty(date)) {
try {
return format.parse(date);
} catch (ParseException e) {
return null;
}
} else {
return null;
}
}
}
package com.mortals.xhx.base.framework;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import java.io.IOException;
import java.text.ParseException;
import java.util.Date;
/**
* 自定义Jackson反序列化日期类型时应用的类型转换器,一般用于@RequestBody接受参数时使用
*/
public class DateJacksonConverter extends JsonDeserializer {
private static String[] pattern = new String[]{"yyyy-MM-dd", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm:ss.S", "yyyy.MM.dd", "yyyy.MM.dd HH:mm", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm:ss.S", "yyyy/MM/dd", "yyyy/MM/dd HH:mm", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm:ss.S"};
@Override
public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Date targetDate = null;
String originDate = p.getText();
if (StringUtils.isNotEmpty(originDate)) {
try {
long longDate = Long.valueOf(originDate.trim());
targetDate = new Date(longDate);
} catch (NumberFormatException e) {
try {
targetDate = DateUtils.parseDate(originDate, DateJacksonConverter.pattern);
} catch (ParseException pe) {
throw new IOException(String.format("'%s' can not convert to type 'java.util.Date',just support timestamp(type of long) and following date format(%s)",
originDate,
StringUtils.join(pattern, ",")));
}
}
}
return targetDate;
}
@Override
public Class handledType() {
return Date.class;
}
}
package com.mortals.xhx.base.framework;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import java.util.ArrayList;
import java.util.List;
/**
* @author: zxfei
* @date: 2022/6/28 15:57
* @description:
**/
// 创建一个新的转换器 解析微信的 [text/plain]
public class WxMessageConverter extends MappingJackson2HttpMessageConverter {
public WxMessageConverter() {
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.TEXT_PLAIN);
setSupportedMediaTypes(mediaTypes);
}
}
\ No newline at end of file
package com.mortals.xhx.base.framework.annotation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)//注解不仅被保存到class文件中,jvm加载class文件之后,仍存在
@Target(ElementType.METHOD) //注解添加的位置
@Documented
public @interface LogPrint {
String description() default "";
}
\ No newline at end of file
package com.mortals.xhx.base.framework.annotation;
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)
public @interface Operlog {
String msg() default "";
String params() default "";
}
package com.mortals.xhx.base.framework.aspect;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.mortals.framework.service.ILogService;
import com.mortals.framework.service.impl.FileLogServiceImpl;
import com.mortals.xhx.base.system.oper.service.OperLogService;
/**
* 操作日志记录
*/
@Component
public class OperlogAspect extends FileLogServiceImpl implements ILogService {
private final static Logger logger = LoggerFactory.getLogger(OperlogAspect.class);
@Autowired
private OperLogService operLogService;
@Override
public void doHandlerLog(String platformMark, Long userId, String userName, String loginName, String requestUrl,
String content, String ip, Date logDate) {
super.doHandlerLog(platformMark, userId, userName, loginName, requestUrl, content, ip, logDate);
operLogService.insertOperLog(ip, requestUrl, userId, userName, loginName, content);
}
@Override
public void doHandlerLog(String platformMark, String loginName, String requestUrl, String content, String ip) {
// operLogService.insertOperLog(ip, requestUrl, null, "", loginName,
// content);
this.doHandlerLog(platformMark, null, "", loginName, requestUrl, content, ip, new Date());
}
@Pointcut("execution(public * com.mortals.xhx..*Controller.*(..))")
public void accessLog() {
}
@Before("accessLog()")
public void doBefore(JoinPoint joinPoint) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// url
logger.info("ip[{}]url[{}]", request.getRemoteAddr(), request.getRequestURL());
// 参数第1和第2个参数为HttpServletRequest request, HttpServletResponse
// response
if (joinPoint.getArgs().length > 2) {
logger.info("args={}", joinPoint.getArgs()[2]);
} else {
logger.info("args={}", joinPoint.getArgs());
}
}
@AfterReturning(returning = "object", pointcut = "accessLog()")
public void doAfterReturning(Object object) {
if (null != object) {
logger.info("response={}", object.toString());
}
}
}
package com.mortals.xhx.base.framework.aspect;
/**
* @author: zxfei
* @date: 2021/8/13 14:47
* @description:
**/
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.mortals.framework.common.code.YesNo;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringEscapeUtils;
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.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.core.io.InputStreamSource;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Spring boot 控制器 请求日志,方便代码调试
*
* @author zxfei
*/
@Slf4j
@Aspect
@Configuration(proxyBeanMethods = false)
@Profile({"develop1", "test"})
public class RequestLogAspect {
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
/**
* AOP 环切 控制器 R 返回值
*
* @param point JoinPoint
* @return Object
* @throws Throwable 异常
*/
@Around("execution(* com.mortals..*Controller.*(..)) || execution(* com.mortals..*Feign.*(..))")
// @Around(
// "execution(!static com.mortals..*Controller.*(..)) && " +
// "(@within(org.springframework.stereotype.Controller) || " +
// "@within(org.springframework.web.bind.annotation.RestController))"
// )
public Object aroundApi(ProceedingJoinPoint point) throws Throwable {
MethodSignature ms = (MethodSignature) point.getSignature();
Method method = ms.getMethod();
Object[] args = point.getArgs();
// 请求参数处理
final Map<String, Object> paraMap = new HashMap<>(16);
for (int i = 0; i < args.length; i++) {
// 读取方法参数
MethodParameter methodParam = getMethodParameter(method, i);
// PathVariable 参数跳过
PathVariable pathVariable = methodParam.getParameterAnnotation(PathVariable.class);
if (pathVariable != null) {
continue;
}
RequestBody requestBody = methodParam.getParameterAnnotation(RequestBody.class);
String parameterName = methodParam.getParameterName();
if (parameterName.equals("binder")) {
continue;
}
Object value = args[i];
// 如果是body的json则是对象
if (requestBody != null && value != null) {
paraMap.putAll(BeanMap.create(value));
continue;
}
// 处理 List
if (value instanceof List) {
value = ((List) value).get(0);
}
// 处理 参数
if (value instanceof HttpServletRequest) {
paraMap.putAll(((HttpServletRequest) value).getParameterMap());
} else if (value instanceof WebRequest) {
paraMap.putAll(((WebRequest) value).getParameterMap());
} else if (value instanceof MultipartFile) {
MultipartFile multipartFile = (MultipartFile) value;
String name = multipartFile.getName();
String fileName = multipartFile.getOriginalFilename();
paraMap.put(name, fileName);
} else if (value instanceof HttpServletResponse) {
} else if (value instanceof InputStream) {
} else if (value instanceof InputStreamSource) {
} else if (value instanceof List) {
List<?> list = (List<?>) value;
AtomicBoolean isSkip = new AtomicBoolean(false);
for (Object o : list) {
if ("StandardMultipartFile".equalsIgnoreCase(o.getClass().getSimpleName())) {
isSkip.set(true);
break;
}
}
if (isSkip.get()) {
paraMap.put(parameterName, "此参数不能序列化为json");
continue;
}
} else {
// 参数名
RequestParam requestParam = methodParam.getParameterAnnotation(RequestParam.class);
String paraName;
if (requestParam != null && StringUtils.isNotBlank(requestParam.value())) {
paraName = requestParam.value();
} else {
paraName = methodParam.getParameterName();
}
paraMap.put(paraName, value);
}
}
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = (requestAttributes == null) ? null : ((ServletRequestAttributes) requestAttributes).getRequest();
String requestURI = Objects.requireNonNull(request).getRequestURI();
String requestMethod = request.getMethod();
// 构建成一条长 日志,避免并发下日志错乱
StringBuilder beforeReqLog = new StringBuilder(300);
// 日志参数
List<Object> beforeReqArgs = new ArrayList<>();
//beforeReqLog.append("\n\n================ Request Start ================\n");
// 打印路由
beforeReqLog.append("Request ===> {}: {}");
beforeReqArgs.add(requestMethod);
beforeReqArgs.add(requestURI);
// 请求参数
if (paraMap.isEmpty()) {
beforeReqLog.append("\n");
} else {
beforeReqLog.append(" Parameters: {}\n");
beforeReqArgs.add(JSON.toJSONString(paraMap, SerializerFeature.DisableCircularReferenceDetect));
}
// 打印请求头
/* Enumeration<String> headers = request.getHeaderNames();
while (headers.hasMoreElements()) {
String headerName = headers.nextElement();
String headerValue = request.getHeader(headerName);
beforeReqLog.append("===Headers=== {} : {}\n");
beforeReqArgs.add(headerName);
beforeReqArgs.add(headerValue);
}*/
//beforeReqLog.append("================ Request End ================\n");
// 打印执行时间
long startNs = System.nanoTime();
log.info(beforeReqLog.toString(), beforeReqArgs.toArray());
// aop 执行后的日志
StringBuilder afterReqLog = new StringBuilder(200);
// 日志参数
List<Object> afterReqArgs = new ArrayList<>();
//afterReqLog.append("\n\n================ Response Start ================\n");
try {
Object result = point.proceed();
// 打印返回结构体
afterReqLog.append("Response===> {}\n");
afterReqArgs.add(StringEscapeUtils.unescapeJava(JSON.toJSONString(result, SerializerFeature.DisableCircularReferenceDetect)));
return result;
} finally {
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
afterReqLog.append("=== {}: {} ({} ms)\n");
afterReqArgs.add(requestMethod);
afterReqArgs.add(requestURI);
afterReqArgs.add(tookMs);
//afterReqLog.append("================ Response End ================\n");
log.info(afterReqLog.toString(), afterReqArgs.toArray());
}
}
/**
* 获取方法参数信息
*
* @param method 方法
* @param parameterIndex 参数序号
* @return {MethodParameter}
*/
public MethodParameter getMethodParameter(Method method, int parameterIndex) {
MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);
methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
return methodParameter;
}
public static void main(String[] args) {
String str = "execution(* com.mortals..*Controller.*(..) && " +
"(@within(org.springframework.stereotype.Controller) || " +
"@within(org.springframework.web.bind.annotation.RestController))";
System.out.println(str);
}
}
\ No newline at end of file
package com.mortals.xhx.base.framework.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mortals.xhx.base.framework.DateJacksonConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
@Configuration
public class ConverterConfig {
@Bean
public DateJacksonConverter dateJacksonConverter() {
return new DateJacksonConverter();
}
@Bean
public Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean(DateJacksonConverter dateJacksonConverter) {
Jackson2ObjectMapperFactoryBean jackson2ObjectMapperFactoryBean = new Jackson2ObjectMapperFactoryBean();
jackson2ObjectMapperFactoryBean.setDeserializers(dateJacksonConverter);
return jackson2ObjectMapperFactoryBean;
}
@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper) {
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
return mappingJackson2HttpMessageConverter;
}
}
package com.mortals.xhx.base.framework.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.*;
/**
* @author: zxfei
* @date: 2022/2/15 13:16
* @description:
**/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Bean
public CorsFilter corsFilter(){
//初始化配置对象
CorsConfiguration configuration = new CorsConfiguration();
//允许跨域访问的域名
configuration.addAllowedOrigin("*");
// configuration.setAllowCredentials(true); //运行携带cookie
configuration.addAllowedMethod("*"); //代表所有请求方法
configuration.addAllowedHeader("*"); //允许携带任何头信息
//初始化cors配置源对象
UrlBasedCorsConfigurationSource configurationSource=new UrlBasedCorsConfigurationSource();
configurationSource.registerCorsConfiguration("/**",configuration);
//返回CorSfilter实例,参数
return new CorsFilter(configurationSource);
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOrigins("*")
.allowedMethods(new String[] { "GET", "POST","PUT","DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 将根路径 "/" 的请求重定向到 "/index.html"
registry.addViewController("/").setViewName("forward:/index.html");
WebMvcConfigurer.super.addViewControllers(registry);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 添加资源处理器,用于映射静态资源路径
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
WebMvcConfigurer.super.addResourceHandlers(registry);
}
}
package com.mortals.xhx.base.framework.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
* 读取代码生成相关配置
*
* @author: zxfei
* @date: 2021/9/28 15:45
*/
@Component
@ConfigurationProperties(prefix = "gen")
@PropertySource(value = {"classpath:generator.yml"})
public class GenConfig {
/**
* 作者
*/
public static String author;
/**
* 生成包路径
*/
public static String packageName;
/**
* 系统包路径
*/
public static String systemPackageName="com.mortals.xhx.base";
/**
* 生成moduleName
*/
public static String moduleName;
/**
* 系统module名称
*/
public static String systemModuleName="system";
/**
* 自动去除表前缀,默认是false
*/
public static boolean autoRemovePre;
/**
* 表前缀(类名不会包含表前缀)
*/
public static String tablePrefix;
public static String systemTable="mortals_xhx_user,mortals_xhx_valid_code,mortals_xhx_uploadfile,mortals_xhx_task," +
"mortals_xhx_table_index,mortals_xhx_role,mortals_xhx_role_auth,mortals_xhx_role_user,mortals_xhx_menu," +
"mortals_xhx_oper_log,mortals_xhx_param,mortals_xhx_idgenerator,mortals_xhx_area,mortals_xhx_resource";
public static String getAuthor() {
return author;
}
@Value("${author}")
public void setAuthor(String author) {
GenConfig.author = author;
}
public static String getPackageName() {
return packageName;
}
@Value("${packageName}")
public void setPackageName(String packageName) {
GenConfig.packageName = packageName;
}
public static String getModuleName() {
return moduleName;
}
@Value("${moduleName}")
public void setModuleName(String moduleName) {
GenConfig.moduleName = moduleName;
}
public static boolean getAutoRemovePre() {
return autoRemovePre;
}
@Value("${autoRemovePre}")
public void setAutoRemovePre(boolean autoRemovePre) {
GenConfig.autoRemovePre = autoRemovePre;
}
public static String getTablePrefix() {
return tablePrefix;
}
@Value("${tablePrefix}")
public void setTablePrefix(String tablePrefix) {
GenConfig.tablePrefix = tablePrefix;
}
public static String getSystemTable() {
return systemTable;
}
@Value("${systemTable}")
public static void setSystemTable(String systemTable) {
GenConfig.systemTable = systemTable;
}
public static String getSystemPackageName() {
return systemPackageName;
}
@Value("${systemPackageName}")
public static void setSystemPackageName(String systemPackageName) {
GenConfig.systemPackageName = systemPackageName;
}
public static String getSystemModuleName() {
return systemModuleName;
}
@Value("${systemModuleName}")
public static void setSystemModuleName(String systemModuleName) {
GenConfig.systemModuleName = systemModuleName;
}
}
package com.mortals.xhx.base.framework.config;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.mortals.framework.util.StringUtils;
@Configuration
public class InterceptorConfig {
/**
* cookie的密钥
*/
@Value("${cookie.key}")
private String securityKey;
/**
* 不需要登录的URL地址,多个用逗号分隔
*/
@Value("${application.auth.unloginUrl}")
private String uncheckLoginUrl;
/**
* 不需要鉴权的URL地址,多个用逗号分隔
*/
@Value("${application.auth.uncheckUrl}")
private String uncheckAuthUrl;
private Set<String> uncheckLoginUrls = new HashSet<>();
private Set<String> uncheckAuthUrls = new HashSet<>();
/**
* 有后缀占位符的不检验地址,如/spi/user/*
*/
private Set<String> uncheckAuthUrlsSuffix = new HashSet<>();
public String getSecurityKey() {
return securityKey;
}
public Set<String> getUncheckLoginUrls() {
return uncheckLoginUrls;
}
public Set<String> getUncheckAuthUrls() {
return uncheckAuthUrls;
}
/**
* 校验地址是否需要权限
*
* @param url
* @return true:需要,false:不需要
*/
public boolean needCheckAuth(String url) {
if (uncheckAuthUrls.contains(url)) {
return false;
}
for (String regexUrl : uncheckAuthUrlsSuffix) {// 支持*结尾
if (url.startsWith(regexUrl)) {
return false;
}
}
return true;
}
@PostConstruct
public void convert() {
uncheckLoginUrls.clear();
uncheckLoginUrls.addAll(StringUtils.converStr2Set(uncheckLoginUrl));
uncheckAuthUrls.clear();
uncheckAuthUrls.addAll(StringUtils.converStr2Set(uncheckAuthUrl));
uncheckAuthUrlsSuffix.clear();
for (String url : uncheckAuthUrls) {
int index = url.indexOf("*");// 支持*结尾
if (index != -1) {
uncheckAuthUrlsSuffix.add(url.substring(0, index));
}
}
}
}
package com.mortals.xhx.base.framework.config;
import com.mortals.framework.springcloud.config.mybatis.AbstractMybatisConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
//@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisConfiguration extends AbstractMybatisConfiguration {
private static Log logger = LogFactory.getLog(MybatisConfiguration.class);
// 配置类型别名
@Value("${spring.application.name}")
private String name;
// 配置类型别名
@Value("${mybatis.root-path}")
private String rootPath;
// 配置类型别名
@Value("${mybatis.type-aliases-package}")
private String typeAliasesPackage;
// 配置mapper的扫描,找到所有的mapper.xml映射文件
@Value("${mybatis.mapper-locations}")
private String mapperLocations;
// 加载全局的配置文件
@Value("${mybatis.config-location}")
private String configLocation;
// 提供SqlSeesion
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("dataSource") DataSource dataSource) {
return super.getSqlSessionFactoryBean(dataSource);
}
@Override
public String getTypeAliasesRootPackage() {
return rootPath;
}
@Override
public String getSqlMappers() {
return mapperLocations;
}
@Override
public String getMybatisConfig() {
return configLocation;
}
@Override
public String getTypeAliasesPackage() {
logger.info("typeAliasesPackage:"+typeAliasesPackage);
return typeAliasesPackage;
}
}
\ No newline at end of file
package com.mortals.xhx.base.framework.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.exception.AppException;
/**
* 统一异常处理
*/
@ControllerAdvice
public class ExceptionHandle {
private final static Logger log = LoggerFactory.getLogger(ExceptionHandle.class);
public static final String KEY_RESULT_CODE = "code";
public static final String KEY_RESULT_MSG = "msg";
public static final String KEY_RESULT_DATA = "data";
public static final int VALUE_RESULT_FAILURE = -1;
@ExceptionHandler(value = Exception.class)
@ResponseBody
public String handle(Exception e) {
JSONObject ret = new JSONObject();
ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
if (e instanceof AppException) {
StackTraceElement stack = e.getStackTrace()[0];
log.error("[business error]=========stack message[{}],[{},method:{},line{}][{}]", e.getMessage(),
stack.getClassName(), stack.getMethodName(), stack.getLineNumber(), e.getClass().getName());
AppException ex = (AppException) e;
ret.put(KEY_RESULT_MSG, ex.getMessage());
} else {
log.error("[system error]", e);
ret.put(KEY_RESULT_MSG, "unknown exception!");
}
return ret.toJSONString();
}
}
package com.mortals.xhx.base.framework.interceptor;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.ap.SysConstains;
import com.mortals.framework.service.IAuthTokenService;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.IUser;
import com.mortals.framework.util.DateUtils;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.resource.service.ResourceService;
import com.mortals.xhx.base.system.user.model.UserEntity;
import com.mortals.xhx.base.system.user.service.UserService;
import com.mortals.xhx.common.key.RedisKey;
import com.mortals.xhx.common.utils.MenuEncodeUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* token验证处理
*
* @author zxfei
*/
@Primary
@Service
@Order(1)
@Slf4j
public class AuthTokenServiceImpl implements IAuthTokenService {
@Autowired
private UserService userService;
// 令牌自定义标识
@Value("${token.header:Authorization}")
private String header;
// 令牌秘钥
@Value("${token.secret:026db82420614469897fcc2dc1b4ce38}")
private String secret;
// 令牌有效期(默认60分钟)
@Value("${token.expireTime:60}")
private int expireTime;
// 令牌前缀
@Value("${token.prefix:}")
private String tokenPrefix;
// redis db
@Value("${spring.redis.database:}")
private Integer db;
@Value("${token.database:0}")
private Integer portalDb;
protected static final Long SECOND = 1000l;
protected static final Long SECOND_MINUTE = 60 * SECOND;
protected static final Long SECOND_HOUR = 60 * SECOND_MINUTE;
protected static final Long SECOND_DAY = 24 * SECOND_HOUR;
protected static final Long SECOND_WEEK = 7 * SECOND_DAY;
private static final Long SECOND_MINUTE_TEN = 1 * SECOND_MINUTE;
@Autowired
private ICacheService cacheService;
@Autowired
private ResourceService resourceService;
/**
* 获取信息
*
* @return 用户信息
*/
@Override
public IUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token)) {
try {
boolean signed = Jwts.parser().isSigned(token);
if (!signed) {
log.error("token非法!=>{}", token);
return null;
}
Claims claims = parseToken(token);
String uuid = (String) claims.get(SysConstains.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
//cacheService.select(portalDb);
String userStr = cacheService.get(userKey);
/* RedisTemplate<String, String> redisTemplate = cacheService.selectDbRedisTemplate(portalDb);
String userStr =redisTemplate.opsForValue().get(userKey);
*/
//刷新token时间
UserEntity userEntity = JSONObject.parseObject(userStr, UserEntity.class);
if (!ObjectUtils.isEmpty(userEntity)) {
verifyToken(userEntity);
}
// cacheService.select(db);
if (!ObjectUtils.isEmpty(userEntity)) {
UserEntity temp = userService.getExtCache(userEntity.getLoginName());
if (!ObjectUtils.isEmpty(temp)) {
userEntity.setId(temp.getId());
}
//更新resource 路径
String menuUrlCode = cacheService.hget(RedisKey.KEY_USER_MENU_CACHE, userEntity.getId().toString(), String.class);
if (ObjectUtils.isEmpty(menuUrlCode)) {
Set<String> urls = resourceService.findUrlSetByUserId(userEntity.getId());
menuUrlCode = MenuEncodeUtil.generateMenuUrlCode(urls);
cacheService.hset(RedisKey.KEY_USER_MENU_CACHE, userEntity.getId().toString(), menuUrlCode);
}
userEntity.setMenuUrl(menuUrlCode);
return userEntity;
}
} catch (Exception e) {
log.error("解析jwt token异常!,token:{}",token, e);
return null;
}
}
return null;
}
/**
* 设置用户信息
*/
@Override
public void setUser(IUser user) {
if (StringUtils.isNotNull(user) && StringUtils.isNotEmpty(user.getToken())) {
refreshToken(user);
}
}
/**
* 删除用户身份信息
*/
@Override
public void delUser(String token) {
if (StringUtils.isNotEmpty(token)) {
String userKey = getTokenKey(token);
cacheService.del(userKey);
}
}
/**
* 创建令牌
*
* @param user 用户信息
* @return 令牌
*/
@Override
public String createToken(IUser user) {
// String token = IdUtil.fastSimpleUUID();
// user.setToken(token);
refreshToken(user);
Map<String, Object> claims = new HashMap<>();
claims.put(SysConstains.LOGIN_USER_KEY, user.getToken());
return createToken(claims);
}
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
*
* @param user
* @return 令牌
*/
@Override
public void verifyToken(IUser user) {
long expireTime = user.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= SECOND_MINUTE_TEN*1000) {
// log.info("不足二十分钟,刷新过期时间");
refreshToken(user);
}
}
/**
* 刷新令牌有效期
*
* @param user 信息
*/
public void refreshToken(IUser user) {
//user.setLoginTime(System.currentTimeMillis());
user.setExpireTime(user.getLoginTime() == null ? System.currentTimeMillis() : user.getLoginTime() + expireTime * SECOND_MINUTE*1000);
// 根据uuid将user缓存
String userKey = getTokenKey(user.getToken());
//设置有效时间 单位秒
cacheService.set(userKey, JSON.toJSONString(user), expireTime * SECOND_MINUTE);
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims) {
String token = Jwts.builder()
.setExpiration(DateUtils.addCurrDate(7))
.setClaims(claims)
.signWith(SignatureAlgorithm.HS256, Base64.getEncoder()
.encodeToString(secret.getBytes())).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
@Override
public Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(Base64.getEncoder().encodeToString(secret.getBytes()))
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户
*
* @param token 令牌
* @return 用户名
*/
@Override
public String getUserNumFromToken(String token) {
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
@Override
public String getToken(HttpServletRequest request) {
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(tokenPrefix)) {
token = token.replace(tokenPrefix, "");
}
return token;
}
private String getTokenKey(String uuid) {
return SysConstains.LOGIN_TOKEN_KEY + uuid;
}
public static void main(String[] args) {
// boolean signed = Jwts.parser().isSigned("123");
boolean signed = Jwts.parser().isSigned("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJuaW5naGFvLm5ldCIsImV4cCI6IjE0Mzg5NTU0NDUiLCJuYW1lIjoid2FuZ2hhbyIsImFkbWluIjp0cnVlfQ.SwyHTEx_RQppr97g4J5lKXtabJecpejuef8AqKYMAJc");
System.out.println(signed);
}
}
package com.mortals.xhx.base.framework.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.annotation.UnAuth;
import com.mortals.framework.common.Rest;
import com.mortals.framework.service.IAuthTokenService;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.IUser;
import com.mortals.framework.util.AESUtil;
import com.mortals.framework.utils.ServletUtils;
import com.mortals.framework.web.interceptor.BaseInterceptor;
import com.mortals.xhx.base.framework.config.InterceptorConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import static com.mortals.xhx.common.key.ErrorCode.*;
/**
* 用户权限验证,基于token
*
* @author: zxfei
* @date: 2022/4/24 11:04
*/
@Component
public class AuthUserInterceptor extends BaseInterceptor {
@Autowired
private InterceptorConfig config;
@Autowired
private IAuthTokenService authTokenService;
@Autowired
private ICacheService cacheService;
@Override
public int getOrder() {
return Integer.MAX_VALUE - 9;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
JSONObject ret = new JSONObject();
if(handler instanceof HandlerMethod){
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
UnAuth annotation = method.getAnnotation(UnAuth.class);
if (annotation != null) {
//取消校验
return true;
}
}else if(handler instanceof ResourceHttpRequestHandler){
return true;
}
try {
String uri = request.getServletPath();
//校验配置的请求路径是否需要检查权限
if (config.needCheckAuth(uri)) {
//需要校验权限
boolean auth = this.checkAuth(request, uri, config.getSecurityKey());
if (!auth) {
//校验token不正常
String token = authTokenService.getToken(request);
if(ObjectUtils.isEmpty(token)){
ServletUtils.renderString(response, JSONObject.toJSONString(Rest.fail(ERROR_TOKEN_UNAUTHORIZED, ERROR_TOKEN_UNAUTHORIZED_CONTENT)));
return false;
}
//不存在时候 如果是管理员也不做拦截
IUser loginUser = authTokenService.getLoginUser(request);
if (ObjectUtils.isEmpty(loginUser)) {
ServletUtils.renderString(response, JSONObject.toJSONString(Rest.fail(ERROR_TOKEN_EXPIRED, ERROR_TOKEN_EXPIRED_CONTENT)));
return false;
// } else if (loginUser.isAdmin() || loginUser.getUserType() == 1) {
} else if (loginUser.isAdmin()) {
return super.preHandle(request, response, handler);
} else {
ServletUtils.renderString(response, JSONObject.toJSONString(Rest.fail(ERROR_USER_OPERATION, ERROR_USER_OPERATION_CONTENT)));
return false;
}
}
}
} catch (Exception e) {
logger.error("权限校验拦截请求处理异常-->" + e.getMessage());
writeJsonResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "用户权限校验异常");
return false;
}
return super.preHandle(request, response, handler);
}
private boolean checkAuth(HttpServletRequest request, String requestUrl, String securityKey) throws Exception {
int code = requestUrl.hashCode() & (Integer.MAX_VALUE - 1);
IUser loginUser = authTokenService.getLoginUser(request);
if (ObjectUtils.isEmpty(loginUser)) return false;
String menuUrl = loginUser.getMenuUrl();
if (ObjectUtils.isEmpty(menuUrl)) return false;
menuUrl = AESUtil.decrypt(menuUrl, securityKey);
String codes = "," + menuUrl + ",";
String codeKey = "," + code + ",";
if (codes.indexOf(codeKey) != -1) {
return true;
}
return false;
}
}
package com.mortals.xhx.base.login.interceptor;
import com.mortals.xhx.base.framework.config.InterceptorConfig;
import com.mortals.framework.ap.CookieService;
import com.mortals.framework.ap.SysConstains;
import com.mortals.framework.model.CookieInfo;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.util.AESUtil;
import com.mortals.framework.util.HttpUtil;
import com.mortals.framework.util.StringUtils;
import com.mortals.framework.web.interceptor.BaseInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Order(1)
@Component
public class AuthJsonInterceptor extends BaseInterceptor {
@Autowired
private InterceptorConfig config;
@Autowired
private ICacheService cacheService;
@Override
public int getOrder() {
return Integer.MAX_VALUE - 9;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
try {
String uri = request.getServletPath();
if (config.needCheckAuth(uri)) {
boolean auth = this.checkAuth(request, uri, config.getSecurityKey());
if (!auth) {
CookieInfo cookie = CookieService.getLoginCookie(request, config.getSecurityKey());
if (cookie == null || cookie.getUser() == null) {
writeJsonResponse(response, HttpServletResponse.SC_FORBIDDEN, "用户未登录或登录失效,请重新登录");
return false;
} else if (cookie.getUser().isAdmin()) {
return super.preHandle(request, response, handler);
} else {
writeJsonResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "用户无该操作权限");
return false;
}
}
}
} catch (Exception e) {
logger.error("权限校验拦截请求处理异常-->" + e.getMessage());
writeJsonResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "用户权限校验异常");
return false;
}
return super.preHandle(request, response, handler);
}
private boolean checkAuth(HttpServletRequest request, String requestUrl, String securityKey) throws Exception {
int code = requestUrl.hashCode() & (Integer.MAX_VALUE - 1);
String cacheKey = HttpUtil.getCookieValue(request, SysConstains.COOKIE_MENU);
if (StringUtils.isEmpty(cacheKey)) {
return false;
}
String menuUrl = cacheService.get(cacheKey);
if (StringUtils.isEmpty(menuUrl)) {
return false;
}
menuUrl = AESUtil.decrypt(menuUrl, securityKey);
String codes = "," + menuUrl + ",";
String codeKey = "," + code + ",";
if (codes.indexOf(codeKey) != -1) {
return true;
}
return false;
}
}
package com.mortals.xhx.base.login.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mortals.xhx.base.framework.config.InterceptorConfig;
import org.springframework.beans.factory.annotation.Autowired;
import com.mortals.framework.ap.CookieService;
import com.mortals.framework.model.CookieInfo;
import com.mortals.framework.service.ITokenService;
import com.mortals.framework.web.interceptor.BaseInterceptor;
//@Component
public class LoginJsonInterceptor extends BaseInterceptor {
@Autowired(required = false)
private ITokenService tokenService;
@Autowired
private InterceptorConfig config;
@Override
public int getOrder() {
return Integer.MAX_VALUE - 10;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
try {
String uri = request.getServletPath();
if (config.needCheckAuth(uri)) {
CookieInfo cookie = CookieService.getLoginCookie(request, config.getSecurityKey());
boolean expire = true;
try {
if (cookie == null || cookie.getUser() == null
|| (cookie != null && tokenService != null && tokenService.isExpireToken(cookie))) {
expire = true;
} else {
expire = false;
}
} catch (Exception e) {
logger.warn("校验cookie是否过期异常-->原因:" + e.getMessage());
}
// 判断用户是否登录
if (expire) {
CookieService.deleteLoginCookie(request, response);
writeJsonResponse(response, HttpServletResponse.SC_FORBIDDEN, "用户未登录或登录失效,请重新登录111333");
return false;
}
}
} catch (Exception e) {
logger.error("登录校验拦截请求处理异常-->" + e.getMessage());
writeJsonResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "用户登录校验异常");
return false;
}
return super.preHandle(request, response, handler);
}
}
package com.mortals.xhx.base.login.service;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* gif动态图验证码图片生成器
*
*/
public class GifSecurityImage {
private static Log logger = LogFactory.getLog(GifSecurityImage.class);
public static BufferedImage createImage(String securityCode) {
int codeLength = securityCode.length();
int fSize = 14;
int fWidth = fSize + 1;
int width = codeLength * fWidth + 6;
int height = fSize * 2 + 1;
BufferedImage image = new BufferedImage(width, height, 1);
Graphics g = image.createGraphics();
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
g.setColor(Color.LIGHT_GRAY);
g.setFont(new Font("Arial", 1, height - 2));
Random rand = new Random();
// 画点
g.setColor(Color.LIGHT_GRAY);
for (int i = 0; i < codeLength * 10; i++) {
g.setColor(randomColor());
int x = rand.nextInt(width);
int y = rand.nextInt(height);
g.drawOval(x, y, 1, 1);
}
for (int i = 0; i < 5; i++) {
g.setColor(randomColor());
int x = rand.nextInt(width - 1);
int y = rand.nextInt(height - 1);
int xl = rand.nextInt(6) + 1;
int yl = rand.nextInt(12) + 1;
g.drawLine(x, y, xl, yl);
}
// 写字
g.setFont(new Font("Georgia", 1, fSize));
for (int i = 0; i < codeLength; i++) {
int codeY = height - 8 - rand.nextInt(5);
int codeX = width / 4 * i + (width / 4 - fSize) / 2;
g.drawString(String.valueOf(securityCode.charAt(i)), codeX, codeY);
}
g.dispose();
return image;
}
public static byte[] createGifImage(String securityCode) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
AnimatedGifEncoder gifEncoder = new AnimatedGifEncoder();
gifEncoder.setRepeat(0);
gifEncoder.start(outputStream);
for (int j = 0; j < 4; j++) {
gifEncoder.setDelay(200); // 设置播放的延迟时间
gifEncoder.addFrame(createImage(securityCode));
}
gifEncoder.finish();
return outputStream.toByteArray();
}
private static Color randomColor() {
Random random = new Random();
int r = random.nextInt(256);
int g = random.nextInt(256);
int b = random.nextInt(256);
return new Color(r, g, b);
}
public static ByteArrayInputStream getImageAsInputStream(String securityCode) {
BufferedImage image = createImage(securityCode);
return convertImageToStream(image);
}
private static ByteArrayInputStream convertImageToStream(BufferedImage image) {
ByteArrayInputStream inputStream = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
byte[] bts = bos.toByteArray();
inputStream = new ByteArrayInputStream(bts);
ImageIO.write(image, "JPG", bos);
} catch (Exception e) {
logger.debug("转换图片数据流异常-->" + e.getMessage());
}
return inputStream;
}
}
package com.mortals.xhx.base.login.service;
import java.io.IOException;
import java.io.OutputStream;
//==============================================================================
// Adapted from Jef Poskanzer's Java port by way of J. M. G. Elliott.
// K Weiner 12/00
class LZWEncoder {
private static final int EOF = -1;
private int imgW, imgH;
private byte[] pixAry;
private int initCodeSize;
private int remaining;
private int curPixel;
// GIFCOMPR.C - GIF Image compression routines
//
// Lempel-Ziv compression based on 'compress'. GIF modifications by
// David Rowley (mgardi@watdcsu.waterloo.edu)
// General DEFINEs
static final int BITS = 12;
static final int HSIZE = 5003; // 80% occupancy
// GIF Image compression - modified 'compress'
//
// Based on: compress.c - File compression ala IEEE Computer, June 1984.
//
// By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
// Jim McKie (decvax!mcvax!jim)
// Steve Davies (decvax!vax135!petsd!peora!srd)
// Ken Turkowski (decvax!decwrl!turtlevax!ken)
// James A. Woods (decvax!ihnp4!ames!jaw)
// Joe Orost (decvax!vax135!petsd!joe)
int n_bits; // number of bits/code
int maxbits = BITS; // user settable max # bits/code
int maxcode; // maximum code, given n_bits
int maxmaxcode = 1 << BITS; // should NEVER generate this code
int[] htab = new int[HSIZE];
int[] codetab = new int[HSIZE];
int hsize = HSIZE; // for dynamic table sizing
int free_ent = 0; // first unused entry
// block compression parameters -- after all codes are used up,
// and compression rate changes, start over.
boolean clear_flg = false;
// Algorithm: use open addressing double hashing (no chaining) on the
// prefix code / next character combination. We do a variant of Knuth's
// algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
// secondary probe. Here, the modular division first probe is gives way
// to a faster exclusive-or manipulation. Also do block compression with
// an adaptive reset, whereby the code table is cleared when the compression
// ratio decreases, but after the table fills. The variable-length output
// codes are re-sized at this point, and a special CLEAR code is generated
// for the decompressor. Late addition: construct the table according to
// file size for noticeable speed improvement on small files. Please direct
// questions about this implementation to ames!jaw.
int g_init_bits;
int ClearCode;
int EOFCode;
// output
//
// Output the given code.
// Inputs:
// code: A n_bits-bit integer. If == -1, then EOF. This assumes
// that n_bits =< wordsize - 1.
// Outputs:
// Outputs code to the file.
// Assumptions:
// Chars are 8 bits long.
// Algorithm:
// Maintain a BITS character long buffer (so that 8 codes will
// fit in it exactly). Use the VAX insv instruction to insert each
// code in turn. When the buffer fills up empty it and start over.
int cur_accum = 0;
int cur_bits = 0;
int masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF,
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
// Number of characters so far in this 'packet'
int a_count;
// Define the storage for the packet accumulator
byte[] accum = new byte[256];
// ----------------------------------------------------------------------------
LZWEncoder(int width, int height, byte[] pixels, int color_depth) {
imgW = width;
imgH = height;
pixAry = pixels;
initCodeSize = Math.max(2, color_depth);
}
// Add a character to the end of the current packet, and if it is 254
// characters, flush the packet to disk.
void char_out(byte c, OutputStream outs) throws IOException {
accum[a_count++] = c;
if (a_count >= 254)
flush_char(outs);
}
// Clear out the hash table
// table clear for block compress
void cl_block(OutputStream outs) throws IOException {
cl_hash(hsize);
free_ent = ClearCode + 2;
clear_flg = true;
output(ClearCode, outs);
}
// reset code table
void cl_hash(int hsize) {
for (int i = 0; i < hsize; ++i)
htab[i] = -1;
}
void compress(int init_bits, OutputStream outs) throws IOException {
int fcode;
int i /* = 0 */;
int c;
int ent;
int disp;
int hsize_reg;
int hshift;
// Set up the globals: g_init_bits - initial number of bits
g_init_bits = init_bits;
// Set up the necessary values
clear_flg = false;
n_bits = g_init_bits;
maxcode = MAXCODE(n_bits);
ClearCode = 1 << (init_bits - 1);
EOFCode = ClearCode + 1;
free_ent = ClearCode + 2;
a_count = 0; // clear packet
ent = nextPixel();
hshift = 0;
for (fcode = hsize; fcode < 65536; fcode *= 2)
++hshift;
hshift = 8 - hshift; // set hash code range bound
hsize_reg = hsize;
cl_hash(hsize_reg); // clear hash table
output(ClearCode, outs);
outer_loop: while ((c = nextPixel()) != EOF) {
fcode = (c << maxbits) + ent;
i = (c << hshift) ^ ent; // xor hashing
if (htab[i] == fcode) {
ent = codetab[i];
continue;
} else if (htab[i] >= 0) // non-empty slot
{
disp = hsize_reg - i; // secondary hash (after G. Knott)
if (i == 0)
disp = 1;
do {
if ((i -= disp) < 0)
i += hsize_reg;
if (htab[i] == fcode) {
ent = codetab[i];
continue outer_loop;
}
} while (htab[i] >= 0);
}
output(ent, outs);
ent = c;
if (free_ent < maxmaxcode) {
codetab[i] = free_ent++; // code -> hashtable
htab[i] = fcode;
} else
cl_block(outs);
}
// Put out the final code.
output(ent, outs);
output(EOFCode, outs);
}
// ----------------------------------------------------------------------------
void encode(OutputStream os) throws IOException {
os.write(initCodeSize); // write "initial code size" byte
remaining = imgW * imgH; // reset navigation variables
curPixel = 0;
compress(initCodeSize + 1, os); // compress and write the pixel data
os.write(0); // write block terminator
}
// Flush the packet to disk, and reset the accumulator
void flush_char(OutputStream outs) throws IOException {
if (a_count > 0) {
outs.write(a_count);
outs.write(accum, 0, a_count);
a_count = 0;
}
}
final int MAXCODE(int n_bits) {
return (1 << n_bits) - 1;
}
// ----------------------------------------------------------------------------
// Return the next pixel from the image
// ----------------------------------------------------------------------------
private int nextPixel() {
if (remaining == 0)
return EOF;
--remaining;
byte pix = pixAry[curPixel++];
return pix & 0xff;
}
void output(int code, OutputStream outs) throws IOException {
cur_accum &= masks[cur_bits];
if (cur_bits > 0)
cur_accum |= (code << cur_bits);
else
cur_accum = code;
cur_bits += n_bits;
while (cur_bits >= 8) {
char_out((byte) (cur_accum & 0xff), outs);
cur_accum >>= 8;
cur_bits -= 8;
}
// If the next entry is going to be too big for the code size,
// then increase it, if possible.
if (free_ent > maxcode || clear_flg) {
if (clear_flg) {
maxcode = MAXCODE(n_bits = g_init_bits);
clear_flg = false;
} else {
++n_bits;
if (n_bits == maxbits)
maxcode = maxmaxcode;
else
maxcode = MAXCODE(n_bits);
}
}
if (code == EOFCode) {
// At EOF, write the rest of the buffer.
while (cur_bits > 0) {
char_out((byte) (cur_accum & 0xff), outs);
cur_accum >>= 8;
cur_bits -= 8;
}
flush_char(outs);
}
}
}
\ No newline at end of file
package com.mortals.xhx.base.login.web;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mortals.framework.common.Rest;
import com.mortals.framework.service.IAuthTokenService;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.service.IUser;
import com.mortals.framework.util.DateUtils;
import com.mortals.framework.util.StringUtils;
import com.mortals.framework.web.BaseCRUDJsonBodyMappingController;
import com.mortals.xhx.base.system.menu.model.MenuEntity;
import com.mortals.xhx.base.system.menu.service.MenuService;
import com.mortals.xhx.base.system.resource.service.ResourceService;
import com.mortals.xhx.base.system.user.model.UserEntity;
import com.mortals.xhx.base.system.user.service.UserService;
import com.mortals.xhx.common.key.RedisKey;
import com.mortals.xhx.common.utils.MenuEncodeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Set;
import static com.mortals.xhx.common.key.ErrorCode.ERROR_TOKEN_EXPIRED;
import static com.mortals.xhx.common.key.ErrorCode.ERROR_TOKEN_EXPIRED_CONTENT;
@RestController
@Slf4j
@RequestMapping("login")
public class LoginController extends BaseCRUDJsonBodyMappingController<UserService, UserEntity, Long> implements InitializingBean {
@Autowired
private ResourceService resourceService;
@Autowired
private MenuService menuService;
@Autowired
private ICacheService cacheService;
@Autowired
private IAuthTokenService authTokenService;
@Autowired
private UserService userService;
@RequestMapping("login")
public String login(@RequestBody LoginForm loginForm) throws Exception {
JSONObject ret = new JSONObject();
JSONObject data = new JSONObject();
String loginName = loginForm.getLoginName();
String password = loginForm.getPassword();
// String securityCode = loginForm.getSecurityCode();
String ip = super.getRequestIP(request);
if (StringUtils.isEmpty(loginName) || StringUtils.isEmpty(password)) {
ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
ret.put(KEY_RESULT_MSG, "未获取到用户信息,请重新登录");
return ret.toJSONString();
}
UserEntity userEntity = null;
try {
// loginForm.validate();
// boolean result = validCodeService.doCheckImageValidCode(request.getSession().getId(), ip, securityCode);
// if (!result) {
// recordSysLog(request, userEntity, "登录验证码不正确或已过期!");
// ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
// ret.put(KEY_RESULT_MSG, "登录验证码不正确或已过期!");
// return ret.toJSONString();
// }
userEntity = userService.doLogin(loginName, password, ip);
userEntity.setLastLoginAddress(ip);
// saveCurrUser(request, response, userEntity);
recordSysLog(request, userEntity, "用户登录系统成功!");
String tmpToken = userEntity.getId() + ":" + IdUtil.fastSimpleUUID();
userEntity.setToken(tmpToken);
userEntity.setExpireTime(DateUtils.addCurrDate(1).getTime());
String token = authTokenService.createToken(userEntity);
data.put("token", token);
// 返回拥有的菜单数据
Set<String> urls = resourceService.findUrlSetByUserId(userEntity.getId());
List<MenuEntity> outlookBarList = menuService.findTreeMenu(userEntity, urls);
String currUserName = userEntity.getRealName();
if (currUserName == null || currUserName.trim().length() == 0) {
currUserName = "管理员";
}
data.put("currUserName", currUserName);
data.put("barList", outlookBarList);
data.put("id", userEntity.getId());
data.put("userType", userEntity.getUserType());
ret.put(KEY_RESULT_DATA, data);
ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
ret.put(KEY_RESULT_MSG, "用户登录系统成功!");
ret.put("resources", urls);
return ret.toJSONString();
} catch (Exception e) {
log.error("login error ", e);
if (userEntity == null) {
userEntity = new UserEntity();
userEntity.setLoginName(loginName);
}
ret.put(KEY_RESULT_CODE, VALUE_RESULT_FAILURE);
ret.put(KEY_RESULT_MSG, super.convertException(e));
return ret.toJSONString();
}
}
@RequestMapping("logout")
public void logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
recordSysLog(request, "退出登录");
super.removeCurrUser(request);
}
@RequestMapping("index")
public String index() throws Exception {
JSONObject ret = new JSONObject();
IUser user = this.getCurUser();
if (user == null) {
return JSONObject.toJSONString(Rest.fail(ERROR_TOKEN_EXPIRED, ERROR_TOKEN_EXPIRED_CONTENT));
}
Set<String> urls = resourceService.findUrlSetByUserId(user.getId());
log.info("userId:{},urls:{}", user.getId(),JSON.toJSONString(urls));
List<MenuEntity> outlookBarList = menuService.findTreeMenu(user, urls);
String currUserName = user.getRealName();
if (currUserName == null || currUserName.trim().length() == 0) {
currUserName = "管理员";
}
JSONObject data = new JSONObject();
String token = authTokenService.getToken(request);
data.put("token", token);
data.put("currUserName", currUserName);
data.put("barList", outlookBarList);
data.put("id", user.getId());
data.put("userType", user.getUserType());
ret.put(KEY_RESULT_DATA, data);
cacheService.hset(RedisKey.KEY_USER_MENU_CACHE, user.getId().toString(), MenuEncodeUtil.generateMenuUrlCode(urls));
ret.put(KEY_RESULT_CODE, VALUE_RESULT_SUCCESS);
ret.put(KEY_RESULT_MSG, "用户登录系统成功!");
ret.put("resources", urls);
return ret.toJSONString();
}
@Override
public void afterPropertiesSet() throws Exception {
log.info("初始化加载登录。。。");
}
}
package com.mortals.xhx.base.login.web;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.web.BaseForm;
public class LoginForm extends BaseForm {
private String loginName;
private String password;
private String securityCode;
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSecurityCode() {
return securityCode;
}
public void setSecurityCode(String securityCode) {
this.securityCode = securityCode;
}
@Override
public String toString() {
return "loginName:" + this.loginName + " password:" + this.password + " securityCode:" + this.securityCode;
}
@Override
public boolean validate() throws AppException {
if (loginName == null || loginName.trim().length() == 0) {
throw new AppException("帐号不能为空!");
}
if (password == null || password.trim().length() == 0) {
throw new AppException("密码不能为空!");
}
if (securityCode == null || securityCode.trim().length() == 0) {
throw new AppException("验证码不能为空!");
}
return super.validate();
}
}
package com.mortals.xhx.base.login.web;
import java.awt.image.BufferedImage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mortals.xhx.base.system.valid.model.ValidCodeEntity;
import com.mortals.xhx.base.system.valid.service.ValidCodeService;
import com.mortals.xhx.base.system.valid.web.ValidCodeForm;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.mortals.framework.util.SecurityImage;
import com.mortals.framework.web.BaseCRUDJsonController;
import com.mortals.xhx.base.login.service.GifSecurityImage;
@RestController
@RequestMapping("securitycode")
public class SecurityCodeController
extends BaseCRUDJsonController<ValidCodeService, ValidCodeForm, ValidCodeEntity, Long> {
@Autowired
private ValidCodeService validCodeService;
@RequestMapping("createCode")
public void createCode(HttpServletRequest request, HttpServletResponse response) {
// 获取默认难度和长度的验证码
String securityCode = validCodeService.createImageValidCode(request.getSession().getId(),
super.getRequestIP(request));
// int imageType = ParamUtil.getInt("securityImage", 1);
int imageType = 0;
switch (imageType) {
case 1:
BufferedImage image = SecurityImage.createImage(securityCode);
super.doResponseImage(response, image);
break;
default:
// 默认图验
byte[] content = GifSecurityImage.createGifImage(securityCode);
doResponseGif(response, content);
break;
}
// // 获取默认难度和长度的验证码
// String securityCode =
// validCodeService.createImageValidCode(request.getSession().getId(),
// super.getRequestIP(request));
// BufferedImage image = SecurityImage.createImage(securityCode);
// super.doResponseImage(response, image);
}
protected void doResponseGif(HttpServletResponse response, byte[] content) {
try {
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "No-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/gif");
IOUtils.write(content, response.getOutputStream());
} catch (Exception e) {
log.error("验证码图片传输异常-->" + e.getMessage());
}
}
}
package com.mortals.xhx.base.system.idgenerator.dao;
import com.mortals.framework.dao.ICRUDDao;
import com.mortals.xhx.base.system.idgenerator.model.IdgeneratorEntity;
/**
* <p>Title: id生成器</p>
* <p>Description: IdgeneratorDao DAO接口 </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
*
* @author
* @version 1.0.0
*/
public interface IdgeneratorDao extends ICRUDDao<IdgeneratorEntity, Long> {
}
\ No newline at end of file
package com.mortals.xhx.base.system.idgenerator.dao.ibatis;
import com.mortals.framework.dao.ibatis.BaseCRUDDaoMybatis;
import com.mortals.xhx.base.system.idgenerator.dao.IdgeneratorDao;
import com.mortals.xhx.base.system.idgenerator.model.IdgeneratorEntity;
import org.springframework.stereotype.Repository;
/**
* <p>Title: id生成器</p>
* <p>Description: IdgeneratorDaoImpl DAO接口 </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
*
* @author
* @version 1.0.0
*/
@Repository("idgeneratorDao")
public class IdgeneratorDaoImpl extends BaseCRUDDaoMybatis<IdgeneratorEntity, Long> implements IdgeneratorDao {
}
\ No newline at end of file
package com.mortals.xhx.base.system.idgenerator.model;
import com.mortals.framework.model.BaseEntityLong;
import java.util.Date;
/**
* <p>Title: id生成器</p>
* <p>Description: IdgeneratorEntity </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
*
* @author
* @version 1.0.0
*/
public class IdgeneratorEntity extends BaseEntityLong {
private static final long serialVersionUID = 1555564885341L;
/** id类型 */
private String idType;
/** 当前id最大值 */
private Long idMaxValue;
/** 备注 */
private String remark;
/** 版本号,默认0 */
private Long versionNum;
/** 最后修改时间 */
private Date gmtModify;
public IdgeneratorEntity() {
}
/**
* 获取 id类型
*
* @return idType
*/
public String getIdType() {
return this.idType;
}
/**
* 设置 id类型
*
* @param idType
*/
public void setIdType(String idType) {
this.idType = idType;
}
/**
* 获取 当前id最大值
*
* @return idMaxValue
*/
public Long getIdMaxValue() {
return this.idMaxValue;
}
/**
* 设置 当前id最大值
*
* @param idMaxValue
*/
public void setIdMaxValue(Long idMaxValue) {
this.idMaxValue = idMaxValue;
}
/**
* 获取 备注
*
* @return remark
*/
public String getRemark() {
return this.remark;
}
/**
* 设置 备注
*
* @param remark
*/
public void setRemark(String remark) {
this.remark = remark;
}
/**
* 获取 版本号,默认0
*
* @return versionNum
*/
public Long getVersionNum() {
return this.versionNum;
}
/**
* 设置 版本号,默认0
*
* @param versionNum
*/
public void setVersionNum(Long versionNum) {
this.versionNum = versionNum;
}
/**
* 获取 最后修改时间
*
* @return gmtModify
*/
public Date getGmtModify() {
return this.gmtModify;
}
/**
* 设置 最后修改时间
*
* @param gmtModify
*/
public void setGmtModify(Date gmtModify) {
this.gmtModify = gmtModify;
}
@Override
public int hashCode() {
return this.getId().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj instanceof IdgeneratorEntity) {
IdgeneratorEntity tmp = (IdgeneratorEntity) obj;
return this.getId().longValue() == tmp.getId().longValue();
}
return false;
}
@Override
public String toString() {
return "IdgeneratorEntity{" + "idType='" + idType + '\'' + ", idMaxValue=" + idMaxValue + ", remark='" + remark
+ '\'' + ", versionNum=" + versionNum + ", gmtModify=" + gmtModify + ", id=" + id + '}';
}
@Override
public void initAttrValue() {
this.idType = null;
this.idMaxValue = null;
this.remark = null;
this.versionNum = 0L;
this.gmtModify = null;
}
}
\ No newline at end of file
package com.mortals.xhx.base.system.idgenerator.model;
import java.util.List;
/**
* <p>Title: id生成器</p>
* <p>Description: IdgeneratorQuery </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
*
* @author
* @version 1.0.0
*/
public class IdgeneratorQuery extends IdgeneratorEntity {
private static final long serialVersionUID = 1555564885342L;
/** 开始 菜单ID,主键,自增长 */
private Long idStart;
/** 结束 菜单ID,主键,自增长 */
private Long idEnd;
/** 增加 菜单ID,主键,自增长 */
private Long idIncrement;
/** 菜单ID,主键,自增长 */
private List<Long> idList;
/** id类型 */
private List<String> idTypeList;
/** 开始 当前id最大值 */
private Long idMaxValueStart;
/** 结束 当前id最大值 */
private Long idMaxValueEnd;
/** 增加 当前id最大值 */
private Long idMaxValueIncrement;
/** 当前id最大值 */
private List<Long> idMaxValueList;
/** 备注 */
private List<String> remarkList;
/** 开始 版本号,默认0 */
private Long versionNumStart;
/** 结束 版本号,默认0 */
private Long versionNumEnd;
/** 增加 版本号,默认0 */
private Long versionNumIncrement;
/** 版本号,默认0 */
private List<Long> versionNumList;
/** 开始 最后修改时间 */
private String gmtModifyStart;
/** 结束 最后修改时间 */
private String gmtModifyEnd;
public IdgeneratorQuery() {
}
/**
* 获取 开始 菜单ID,主键,自增长
*
* @return idStart
*/
public Long getIdStart() {
return this.idStart;
}
/**
* 设置 开始 菜单ID,主键,自增长
*
* @param idStart
*/
public void setIdStart(Long idStart) {
this.idStart = idStart;
}
/**
* 获取 结束 菜单ID,主键,自增长
*
* @return idEnd
*/
public Long getIdEnd() {
return this.idEnd;
}
/**
* 设置 结束 菜单ID,主键,自增长
*
* @param idEnd
*/
public void setIdEnd(Long idEnd) {
this.idEnd = idEnd;
}
/**
* 获取 增加 菜单ID,主键,自增长
*
* @return idIncrement
*/
public Long getIdIncrement() {
return this.idIncrement;
}
/**
* 设置 增加 菜单ID,主键,自增长
*
* @param idIncrement
*/
public void setIdIncrement(Long idIncrement) {
this.idIncrement = idIncrement;
}
/**
* 获取 菜单ID,主键,自增长
*
* @return idList
*/
public List<Long> getIdList() {
return this.idList;
}
/**
* 设置 菜单ID,主键,自增长
*
* @param idList
*/
public void setIdList(List<Long> idList) {
this.idList = idList;
}
/**
* 获取 id类型
*
* @return idTypeList
*/
public List<String> getIdTypeList() {
return this.idTypeList;
}
/**
* 设置 id类型
*
* @param idTypeList
*/
public void setIdTypeList(List<String> idTypeList) {
this.idTypeList = idTypeList;
}
/**
* 获取 开始 当前id最大值
*
* @return idMaxValueStart
*/
public Long getIdMaxValueStart() {
return this.idMaxValueStart;
}
/**
* 设置 开始 当前id最大值
*
* @param idMaxValueStart
*/
public void setIdMaxValueStart(Long idMaxValueStart) {
this.idMaxValueStart = idMaxValueStart;
}
/**
* 获取 结束 当前id最大值
*
* @return idMaxValueEnd
*/
public Long getIdMaxValueEnd() {
return this.idMaxValueEnd;
}
/**
* 设置 结束 当前id最大值
*
* @param idMaxValueEnd
*/
public void setIdMaxValueEnd(Long idMaxValueEnd) {
this.idMaxValueEnd = idMaxValueEnd;
}
/**
* 获取 增加 当前id最大值
*
* @return idMaxValueIncrement
*/
public Long getIdMaxValueIncrement() {
return this.idMaxValueIncrement;
}
/**
* 设置 增加 当前id最大值
*
* @param idMaxValueIncrement
*/
public void setIdMaxValueIncrement(Long idMaxValueIncrement) {
this.idMaxValueIncrement = idMaxValueIncrement;
}
/**
* 获取 当前id最大值
*
* @return idMaxValueList
*/
public List<Long> getIdMaxValueList() {
return this.idMaxValueList;
}
/**
* 设置 当前id最大值
*
* @param idMaxValueList
*/
public void setIdMaxValueList(List<Long> idMaxValueList) {
this.idMaxValueList = idMaxValueList;
}
/**
* 获取 备注
*
* @return remarkList
*/
public List<String> getRemarkList() {
return this.remarkList;
}
/**
* 设置 备注
*
* @param remarkList
*/
public void setRemarkList(List<String> remarkList) {
this.remarkList = remarkList;
}
/**
* 获取 开始 版本号,默认0
*
* @return versionNumStart
*/
public Long getVersionNumStart() {
return this.versionNumStart;
}
/**
* 设置 开始 版本号,默认0
*
* @param versionNumStart
*/
public void setVersionNumStart(Long versionNumStart) {
this.versionNumStart = versionNumStart;
}
/**
* 获取 结束 版本号,默认0
*
* @return versionNumEnd
*/
public Long getVersionNumEnd() {
return this.versionNumEnd;
}
/**
* 设置 结束 版本号,默认0
*
* @param versionNumEnd
*/
public void setVersionNumEnd(Long versionNumEnd) {
this.versionNumEnd = versionNumEnd;
}
/**
* 获取 增加 版本号,默认0
*
* @return versionNumIncrement
*/
public Long getVersionNumIncrement() {
return this.versionNumIncrement;
}
/**
* 设置 增加 版本号,默认0
*
* @param versionNumIncrement
*/
public void setVersionNumIncrement(Long versionNumIncrement) {
this.versionNumIncrement = versionNumIncrement;
}
/**
* 获取 版本号,默认0
*
* @return versionNumList
*/
public List<Long> getVersionNumList() {
return this.versionNumList;
}
/**
* 设置 版本号,默认0
*
* @param versionNumList
*/
public void setVersionNumList(List<Long> versionNumList) {
this.versionNumList = versionNumList;
}
/**
* 获取 开始 最后修改时间
*
* @return gmtModifyStart
*/
public String getGmtModifyStart() {
return this.gmtModifyStart;
}
/**
* 设置 开始 最后修改时间
*
* @param gmtModifyStart
*/
public void setGmtModifyStart(String gmtModifyStart) {
this.gmtModifyStart = gmtModifyStart;
}
/**
* 获取 结束 最后修改时间
*
* @return gmtModifyEnd
*/
public String getGmtModifyEnd() {
return this.gmtModifyEnd;
}
/**
* 设置 结束 最后修改时间
*
* @param gmtModifyEnd
*/
public void setGmtModifyEnd(String gmtModifyEnd) {
this.gmtModifyEnd = gmtModifyEnd;
}
}
\ No newline at end of file
package com.mortals.xhx.base.system.idgenerator.service;
import java.util.List;
import com.mortals.xhx.base.system.idgenerator.service.impl.IdgeneratorServiceImpl.IdGeneratorKey;
/**
* <p>Title: id生成器</p>
* <p>Description: IdgeneratorService service接口 </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
*
* @author
* @version 1.0.0
*/
public interface IdgeneratorService {
/**
* 获取Long类型ID
*
* @param idGeneratorKey
* @param factorInfo 生成因子,根据各IdGeneratorKey要求选择传入
* @return
* @createTime 2016年3月16日 上午10:43:22
*/
Long getLongId(IdGeneratorKey idGeneratorKey, Object... factorInfo);
/**
* 获取String类型ID
*
* @param idGeneratorKey
* @param factorInfo 生成因子,根据各IdGeneratorKey要求选择传入
* @return
* @createTime 2016年3月16日 上午10:43:38
*/
String getStringId(IdGeneratorKey idGeneratorKey, Object... factorInfo);
/**
* 批量获取Long类型ID
*
* @param idGeneratorKey
* @param factorInfo
* @return
*/
List<Long> getLongIdList(IdGeneratorKey idGeneratorKey, Object... factorInfo);
}
\ No newline at end of file
package com.mortals.xhx.base.system.menu.dao;
import com.mortals.framework.dao.ICRUDDao;
import com.mortals.xhx.base.system.menu.model.MenuEntity;
import java.util.List;
/**
* 菜单信息Dao
* 菜单信息 DAO接口
*
* @author zxfei
* @date 2023-04-10
*/
public interface MenuDao extends ICRUDDao<MenuEntity,Long>{
/**
* 查询子节点
*
* @param
* @return
*/
List<MenuEntity> selectChildrenMenuById(String menuId);
}
package com.mortals.xhx.base.system.menu.dao.ibatis;
import com.mortals.framework.dao.ibatis.BaseCRUDDaoMybatis;
import com.mortals.xhx.base.system.menu.dao.MenuDao;
import com.mortals.xhx.base.system.menu.model.MenuEntity;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 菜单信息DaoImpl DAO接口
*
* @author zxfei
* @date 2023-04-10
*/
@Repository("menuDao")
public class MenuDaoImpl extends BaseCRUDDaoMybatis<MenuEntity,Long> implements MenuDao {
@Override
public List<MenuEntity> selectChildrenMenuById(String menuId) {
return getSqlSession().selectList(getSqlId("selectChildrenMenuById"), menuId);
}
}
package com.mortals.xhx.base.system.menu.model;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
/**
* 菜单信息前端映射树结构实体类
*
* @author zxfei
* @date 2023-04-10
*/
@Data
public class MenuTreeSelect implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 节点ID
*/
private Long id;
/**
* 节点名称
*/
private String label;
/**
* 子节点
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<MenuTreeSelect> children;
public MenuTreeSelect(MenuEntity entity) {
this.id = entity.getId();
this.label = entity.getName();
this.children = entity.getChildList().stream().map(MenuTreeSelect::new).collect(Collectors.toList());
}
}
\ No newline at end of file
package com.mortals.xhx.base.system.menu.model.vo;
import com.mortals.framework.model.BaseEntityLong;
import com.mortals.xhx.base.system.menu.model.MenuEntity;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 菜单信息视图对象
*
* @author zxfei
* @date 2023-04-10
*/
@Data
public class MenuVo extends BaseEntityLong {
/** 子菜单信息 */
private List<MenuEntity> childList = new ArrayList<>();
private Integer type;
}
\ No newline at end of file
package com.mortals.xhx.base.system.menu.service;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.ICRUDService;
import com.mortals.framework.service.IUser;
import com.mortals.xhx.base.system.menu.model.MenuEntity;
import com.mortals.xhx.base.system.menu.model.MenuTreeSelect;
import java.util.List;
import java.util.Set;
/**
* MenuService
* <p>
* 菜单信息 service接口
*
* @author zxfei
* @date 2023-04-10
*/
public interface MenuService extends ICRUDService<MenuEntity, Long> {
/**
* 获取所有可用菜单
*
* @return
* @throws AppException
*/
public List<MenuEntity> findAllEnable() throws AppException;
/**
* 查询有权限的菜单
*
* @param user 当前用户
* @param urls 有权限的访问地址集合
* @return
* @throws AppException
*/
public List<MenuEntity> findTreeMenu(IUser user, Set<String> urls) throws AppException;
/**
* 查看所有菜单
*
* @return
* @throws AppException
*/
public List<MenuEntity> findTreeMenu() throws AppException;
/**
* 更新排列顺序
*
* @param id
* @param type
*/
void upOrDown(Long id, Integer type);
/**
* 是否存在菜单信息节点
*
* @param menuId 菜单信息ID
* @return 结果
*/
boolean hasChildByMenuId(Long menuId);
/**
* 查询菜单信息数据
*
* @param menu 菜单信息
* @return 菜单信息集合
*/
List<MenuEntity> selectMenuList(MenuEntity menu);
/**
* 构建前端所需要下拉树结构
*
* @param menuList 菜单信息列表
* @return 下拉树结构列表
*/
List<MenuTreeSelect> buildMenuTreeSelect(List<MenuEntity> menuList);
/**
* 根据父id查询子节点
*
* @param parentId
* @param context
* @return
*/
List<MenuTreeSelect> getListByParentId(Long parentId, Context context);
Set<Long> getPathSetById(Long id, Context context);
}
\ No newline at end of file
/**
* 文件:MenuForm.java
* 版本:1.0.0
* 日期:
* Copyright &reg;
* All right reserved.
*/
package com.mortals.xhx.base.system.menu.web;
import com.mortals.framework.web.BaseCRUDFormLong;
import com.mortals.xhx.base.system.menu.model.MenuEntity;
import com.mortals.xhx.base.system.menu.model.MenuQuery;
/**
* <p>Title: 菜单信息</p>
* <p>Description: MenuForm </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
* @author
* @version 1.0.0
*/
public class MenuForm extends BaseCRUDFormLong<MenuEntity> {
private MenuEntity entity = new MenuEntity();
private MenuQuery query = new MenuQuery();
public MenuForm(){
}
@Override
public MenuEntity getEntity() {
return entity;
}
public void setEntity(MenuEntity entity) {
this.entity = entity;
}
@Override
public MenuQuery getQuery() {
return query;
}
public void setQuery(MenuQuery query) {
this.query = query;
}
}
\ No newline at end of file
/**
* 文件:OperLogDao.java
* 版本:1.0.0
* 日期:
* Copyright &reg;
* All right reserved.
*/
package com.mortals.xhx.base.system.oper.dao;
import com.mortals.framework.dao.ICRUDDao;
import com.mortals.xhx.base.system.oper.model.OperLogEntity;
/**
* <p>Title: 操作日志</p>
* <p>Description: OperLogDao DAO接口 </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
* @author
* @version 1.0.0
*/
public interface OperLogDao extends ICRUDDao<OperLogEntity,Long> {
}
\ No newline at end of file
/**
* 文件:ParamDao.java
* 版本:1.0.0
* 日期:
* Copyright &reg;
* All right reserved.
*/
package com.mortals.xhx.base.system.param.dao;
import com.mortals.framework.dao.ICRUDDao;
import com.mortals.xhx.base.system.param.model.ParamEntity;
/**
* <p>Title: 参数信息</p>
* <p>Description: ParamDao DAO接口 </p>
* <p>Copyright: Copyright &reg; </p>
* <p>Company: </p>
* @author
* @version 1.0.0
*/
public interface ParamDao extends ICRUDDao<ParamEntity,Long> {
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment