完善基础代码

This commit is contained in:
wanggeng888 2021-02-09 23:54:18 +08:00
parent 97e10edd80
commit 502c180912
34 changed files with 2624 additions and 20 deletions

View File

@ -0,0 +1,24 @@
package ink.wgink.interfaces.consts;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: IFileConstant
* @Description: 文件常量
* @Author: wanggeng
* @Date: 2021/2/9 8:15 下午
* @Version: 1.0
*/
public interface IFileConstant {
/**
* Excel .xls 后缀
*/
String EXCEL_SUFFIX_XLS = ".xls";
/**
* Excel .xlsx 后缀
*/
String EXCEL_SUFFIX_XLSX = ".xlsx";
}

View File

@ -43,6 +43,22 @@ public interface IUserBaseService {
*/
List<UserDTO> listByUserIds(List<String> userIds);
/**
* 用户列表
*
* @param usernames 用户名列表
* @return
*/
List<UserDTO> listByUsernames(List<String> usernames);
/**
* 用户列表
*
* @param params 参数
* @return
*/
List<UserDTO> list(Map<String, Object> params);
/**
* 用户分页列表
*

View File

@ -4,6 +4,9 @@ import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
/**
* @ClassName: RequestUtil
@ -64,4 +67,25 @@ public class RequestUtil {
return ip;
}
/**
* 下载
*
* @param response 响应
* @param outFile 输出的文件
* @param outFileName 输出的名字
*/
public static void download(HttpServletResponse response, File outFile, String outFileName) throws IOException {
try (FileInputStream fileInputStream = new FileInputStream(outFile);
OutputStream outputStream = response.getOutputStream()) {
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(outFileName, "UTF-8"));
byte[] buf = new byte[1024];
for (int readLength; (readLength = fileInputStream.read(buf)) > 0; ) {
outputStream.write(buf, 0, readLength);
}
outputStream.flush();
}
}
}

View File

@ -4,9 +4,12 @@ import com.alibaba.fastjson.JSON;
import ink.wgink.common.enums.ErrorResultCodeEnum;
import ink.wgink.exceptions.*;
import ink.wgink.exceptions.base.SystemException;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.pojo.result.ErrorResult;
import ink.wgink.util.AesUtil;
import ink.wgink.util.map.HashMapUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
@ -20,7 +23,14 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLSyntaxErrorException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
@ -43,6 +53,8 @@ public class ResponseAdvice {
}
if (e instanceof FileException) {
LOG.error(e.getMessage());
} else if(e instanceof ParamsException){
LOG.error(e.getMessage());
} else {
LOG.error(e.getMessage(), e);
}
@ -88,6 +100,7 @@ public class ResponseAdvice {
}
String contentType = request.getContentType();
if (contentType != null && contentType.contains(MediaType.APPLICATION_JSON_VALUE)) {
response.setCharacterEncoding(ISystemConstant.CHARSET_UTF8);
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpStatus.BAD_REQUEST.value());
response.getWriter().write(JSON.toJSONString(result));

View File

@ -0,0 +1,310 @@
package ink.wgink.common.aspect;
import ink.wgink.annotation.*;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.util.RegexUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
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.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ApiParamsAspect
* @Description: api接口
* @Author: WangGeng
* @Date: 2019/11/14 15:36
* @Version: 1.0
**/
@Aspect
@Component
@Order(1)
public class ApiParamsAspect {
private static final Logger LOG = LoggerFactory.getLogger(ApiParamsAspect.class);
@Pointcut("execution(public * *..*Controller.*(..))")
public void apiCutPoint() {
}
@Before("apiCutPoint()")
public void beforeApiCutPoint(JoinPoint joinPoint) throws ParamsException {
beforeCutPoint(joinPoint);
}
private void beforeCutPoint(JoinPoint joinPoint) throws ParamsException {
Signature signature = joinPoint.getSignature();
Object[] args = joinPoint.getArgs();
Class<?> targetClazz = joinPoint.getTarget().getClass();
Method method = getMethod(signature.getName(), targetClazz.getMethods(), args);
if (method == null) {
return;
}
if (method.isAnnotationPresent(CheckRequestBodyAnnotation.class)) {
LOG.debug("校验参数");
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
if (parameter.isAnnotationPresent(RequestBody.class)) {
for (Object arg : args) {
if (parameter.getType() == arg.getClass()) {
checkField(arg);
}
}
}
}
}
}
private Method getMethod(String methodName, Method[] methods, Object[] args) {
for (Method method : methods) {
Class<?>[] parameterTypes = method.getParameterTypes();
// 方法名称相同
if (StringUtils.equals(methodName, method.getName())) {
// 参数长度相同
if (args.length == parameterTypes.length) {
// 参数类型顺序相同
boolean isThisMethod = true;
for (int argIndex = 0; argIndex < args.length; argIndex++) {
if (!parameterTypes[argIndex].isInstance(args[argIndex])) {
isThisMethod = false;
break;
}
}
if (isThisMethod) {
return method;
}
}
}
}
return null;
}
/**
* 校验字段
*
* @param object
* @throws ParamsException
*/
public void checkField(Object object) throws ParamsException {
Class<?> clazz = object.getClass();
List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
setSuperClassField(clazz, fields);
Method[] methods = clazz.getMethods();
try {
for (Field field : fields) {
Method method = getGetMethodByField(methods, field.getName());
if (method == null) {
continue;
}
Object fieldValue = method.invoke(object);
if (field.isAnnotationPresent(CheckNullAnnotation.class)) {
CheckNullAnnotation checkNullAnnotation = field.getAnnotation(CheckNullAnnotation.class);
if (fieldValue == null) {
throw new ParamsException(String.format("%s不能为空", checkNullAnnotation.name()));
}
checkTypes(checkNullAnnotation.name(), fieldValue.toString(), checkNullAnnotation.types());
} else if (field.isAnnotationPresent(CheckEmptyAnnotation.class)) {
CheckEmptyAnnotation checkEmptyAnnotation = field.getAnnotation(CheckEmptyAnnotation.class);
if (fieldValue == null || StringUtils.isBlank(fieldValue.toString())) {
throw new ParamsException(String.format("%s不能为空或空串", checkEmptyAnnotation.name()));
}
checkRegular(checkEmptyAnnotation.name(), fieldValue.toString(), checkEmptyAnnotation.verifyType(), checkEmptyAnnotation.regex());
checkTypes(checkEmptyAnnotation.name(), fieldValue.toString(), checkEmptyAnnotation.types());
} else if (field.isAnnotationPresent(CheckNumberAnnotation.class)) {
CheckNumberAnnotation checkNumberAnnotation = field.getAnnotation(CheckNumberAnnotation.class);
if (fieldValue == null || !NumberUtils.isNumber(fieldValue.toString())) {
throw new ParamsException(String.format("%s必须为数字", checkNumberAnnotation.name()));
}
Double value = Double.parseDouble(fieldValue.toString());
if (value < checkNumberAnnotation.min()) {
throw new ParamsException(String.format("%s最小值为%f", checkNumberAnnotation.name(), checkNumberAnnotation.min()));
}
if (value > checkNumberAnnotation.max()) {
throw new ParamsException(String.format("%s最大值为%f", checkNumberAnnotation.name(), checkNumberAnnotation.max()));
}
checkTypes(checkNumberAnnotation.name(), fieldValue.toString(), checkNumberAnnotation.types());
} else if (field.isAnnotationPresent(CheckBooleanAnnotation.class)) {
CheckBooleanAnnotation checkBooleanAnnotation = field.getAnnotation(CheckBooleanAnnotation.class);
if (fieldValue == null) {
throw new ParamsException(String.format("%s必须为布尔", checkBooleanAnnotation.name()));
}
checkTypes(checkBooleanAnnotation.name(), fieldValue.toString(), checkBooleanAnnotation.types());
} else if (field.isAnnotationPresent(CheckListAnnotation.class)) {
CheckListAnnotation checkListAnnotation = field.getAnnotation(CheckListAnnotation.class);
if (fieldValue == null) {
throw new ParamsException(String.format("%s不能为空", checkListAnnotation.name()));
}
if (fieldValue instanceof List) {
List fieldValueList = (List) fieldValue;
if (fieldValueList.isEmpty()) {
throw new ParamsException(String.format("%s不能为空", checkListAnnotation.name()));
}
for (Object obj : fieldValueList) {
checkField(obj);
}
} else if (fieldValue instanceof String[]) {
String[] fieldValueArray = (String[]) fieldValue;
for (Object obj : fieldValueArray) {
checkField(obj);
}
}
}
}
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
throw new ParamsException("系统错误");
}
}
/**
* 检查类型
*
* @param name
* @param value
* @param types
* @throws ParamsException
*/
private void checkTypes(String name, String value, String[] types) throws ParamsException {
if (types != null && types.length > 0) {
StringBuilder typeSB = new StringBuilder();
for (String type : types) {
if (StringUtils.equals(value, type)) {
return;
}
if (typeSB.length() > 0) {
typeSB.append(",");
}
typeSB.append("\"").append(type).append("\"");
}
throw new ParamsException(String.format("%s必须是如下类型[%s]", name, typeSB.toString()));
}
}
/**
* 检查正则
*
* @param name
* @param value
* @param verifyType
* @param regex
*/
private void checkRegular(String name, String value, String verifyType, String regex) {
if (StringUtils.isBlank(verifyType)) {
return;
}
if (StringUtils.equals("username", verifyType)) {
if (!RegexUtil.isUsername(value)) {
throw new ParamsException(String.format("%s格式只能是字母、数字和下划线", name));
}
return;
} else if (StringUtils.equals("phone", verifyType)) {
if (!RegexUtil.isPhone(value)) {
throw new ParamsException(String.format("%s格式非手机格式", name));
}
return;
} else if (StringUtils.equals("email", verifyType)) {
if (!RegexUtil.isEmail(value)) {
throw new ParamsException(String.format("%s格式非邮件格式", name));
}
return;
} else if (StringUtils.equals("url", verifyType)) {
if (!RegexUtil.isUrl(value)) {
throw new ParamsException(String.format("%s格式非url格式", name));
}
return;
} else if (StringUtils.equals("number", verifyType)) {
if (!NumberUtils.isNumber(value)) {
throw new ParamsException(String.format("%s格式非数字格式", name));
}
return;
} else if (StringUtils.equals("date", verifyType)) {
if (!RegexUtil.isDate(value)) {
throw new ParamsException(String.format("%s格式非日期格式", name));
}
return;
} else if (StringUtils.equals("datetime", verifyType)) {
if (!RegexUtil.isDatetime(value)) {
throw new ParamsException(String.format("%s格式非时间戳格式", name));
}
return;
} else if (StringUtils.equals("identity", verifyType)) {
if (!RegexUtil.isIdentity(value)) {
throw new ParamsException(String.format("%s格式非身份证格式", name));
}
return;
} else if (StringUtils.equals("letter", verifyType)) {
if (!RegexUtil.isLetter(value)) {
throw new ParamsException(String.format("%s格式非字母格式", name));
}
return;
} else if (StringUtils.equals("chinese", verifyType)) {
if (!RegexUtil.isLetter(value)) {
throw new ParamsException(String.format("%s格式非中文格式", name));
}
return;
} else if (StringUtils.equals("custom", verifyType)) {
if (StringUtils.isBlank(regex)) {
return;
}
if (!Pattern.compile(regex).matcher(value).matches()) {
throw new ParamsException(String.format("%s格式不正确", name));
}
}
}
/**
* 通过字段获取get方法
*
* @param methods
* @param fieldName
* @return
*/
public Method getGetMethodByField(Method[] methods, String fieldName) {
String getMethodName = String.format("get%s", fieldName).toLowerCase();
for (Method method : methods) {
if (StringUtils.equals(getMethodName, method.getName().toLowerCase())) {
return method;
}
}
return null;
}
/**
* 设置父类属性列表
*
* @param clazz
* @param fields
*/
private void setSuperClassField(Class<?> clazz, List<Field> fields) {
Class<?> superClazz = clazz.getSuperclass();
if (superClazz == null) {
return;
}
Field[] superFields = superClazz.getDeclaredFields();
if (superFields == null) {
return;
}
fields.addAll(Arrays.asList(superFields));
setSuperClassField(superClazz, fields);
}
}

View File

@ -6,7 +6,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
@ -21,7 +24,7 @@ import java.util.Map;
* @Date: 2018/9/27 下午3:47
* @Version: 1.0
**/
@Component
@Controller
public class DefaultBaseController {
protected static final Logger LOG = LoggerFactory.getLogger(DefaultBaseController.class);
@ -29,6 +32,12 @@ public class DefaultBaseController {
@Autowired
private HttpSession httpSession;
@GetMapping("index")
public ModelAndView goIndex() {
ModelAndView mv = new ModelAndView("index");
return mv;
}
/**
* 获取请求参数
*

View File

@ -80,7 +80,11 @@ public class DefaultBaseService {
*/
protected void setUpdateInfo(Map<String, Object> params) {
UserInfoBO userInfoBO = securityComponent.getCurrentUser();
setUpdate(userInfoBO.getUserId(), params);
if (userInfoBO != null) {
setUpdate(userInfoBO.getUserId(), params);
} else {
setUpdate("1", params);
}
}
/**

View File

@ -0,0 +1,73 @@
package ink.wgink.common.config;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: BeanConfig
* @Description: bean配置
* @Author: wanggeng
* @Date: 2021/2/5 6:44 下午
* @Version: 1.0
*/
@Configuration
public class BeanConfig {
@Bean
public HttpMessageConverter configureMessageConverters() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
// 保留map空的字段
SerializerFeature.WriteMapNullValue,
// 将String类型的null转成""
SerializerFeature.WriteNullStringAsEmpty,
// 将Number类型的null转成0
SerializerFeature.WriteNullNumberAsZero,
// 将List类型的null转成[]
SerializerFeature.WriteNullListAsEmpty,
// 将Boolean类型的null转成false
SerializerFeature.WriteNullBooleanAsFalse,
// 避免循环引用
SerializerFeature.DisableCircularReferenceDetect);
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
List<MediaType> mediaTypeList = new ArrayList<>();
// 解决中文乱码问题相当于在Controller上的@RequestMapping中加了个属性produces = "application/json"
mediaTypeList.add(MediaType.APPLICATION_JSON);
converter.setSupportedMediaTypes(mediaTypeList);
return converter;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return true;
}
};
// return new BCryptPasswordEncoder();
}
}

View File

@ -63,9 +63,10 @@ public class TransactionConfig {
public TransactionInterceptor txAdvice() {
DefaultTransactionAttribute required = new DefaultTransactionAttribute();
required.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
required.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
DefaultTransactionAttribute readOnly = new DefaultTransactionAttribute();
readOnly.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
required.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
readOnly.setReadOnly(true);
List<String> saveList = transactionProperties.getSaveList();
@ -104,11 +105,11 @@ public class TransactionConfig {
@Bean
public Advisor txAdviceAdvisor() {
StringBuilder expressionSB = new StringBuilder("execution(* ink.wgink..*.service..*(..))");
List<String> servicePackageList = transactionProperties.getServicePackageList();
for (String servicePackage : servicePackageList) {
expressionSB.append(" or execution(* " + servicePackage + "..*.service..*(..))");
}
StringBuilder expressionSB = new StringBuilder("execution(* *..service..*(..))");
// List<String> servicePackageList = transactionProperties.getServicePackageList();
// for (String servicePackage : servicePackageList) {
// expressionSB.append(" or execution(* " + servicePackage + "..*.service..*(..))");
// }
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(expressionSB.toString());

View File

@ -0,0 +1,31 @@
package ink.wgink.common.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: WebConfig
* @Description: Web配置
* @Author: wanggeng
* @Date: 2021/2/5 7:44 下午
* @Version: 1.0
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/static/assets/").setCachePeriod(7 * 24 * 3600);
}
}

View File

@ -22,6 +22,11 @@ import java.util.Map;
@Repository
public interface IFileDao {
/**
* 建表
*/
void createTable();
/**
* 保存文件
*
@ -99,5 +104,4 @@ public interface IFileDao {
*/
List<FileInfoDTO> listByMd5(String fileMd5) throws SearchException;
}

View File

@ -3,6 +3,7 @@ package ink.wgink.module.file.excel.error;
import com.alibaba.excel.EasyExcel;
import ink.wgink.module.file.service.IFileService;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.request.RequestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -0,0 +1,45 @@
package ink.wgink.module.file.startup;
import ink.wgink.module.file.dao.IFileDao;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.util.date.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ModuleFileStartUp
* @Description: 文件模块启动
* @Author: wanggeng
* @Date: 2021/2/9 9:18 下午
* @Version: 1.0
*/
@Component
public class ModuleFileStartUp implements ApplicationRunner {
private static final Logger LOG = LoggerFactory.getLogger(ModuleFileStartUp.class);
@Autowired
private IFileDao fileDao;
@Override
public void run(ApplicationArguments args) throws Exception {
initTable();
}
/**
* 建表
*/
private void initTable() {
LOG.debug("创建 sys_file 表");
fileDao.createTable();
}
}

View File

@ -0,0 +1,279 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="ink.wgink.module.file.dao.IFileDao">
<cache/>
<resultMap id="filePO" type="ink.wgink.pojo.pos.FilePO">
<id property="fileId" column="file_id"/>
<result property="fileName" column="file_name"/>
<result property="filePath" column="file_path"/>
<result property="fileUrl" column="file_url"/>
<result property="fileType" column="file_type"/>
<result property="fileSize" column="file_size"/>
<result property="fileSummary" column="file_summary"/>
<result property="isBack" column="is_back"/>
<result property="creator" column="creator"/>
<result property="gmtCreate" column="gmt_create"/>
<result property="modifier" column="modifier"/>
<result property="gmtModified" column="gmt_modified"/>
<result property="isDelete" column="is_delete"/>
</resultMap>
<resultMap id="fileDTO" type="ink.wgink.module.file.pojo.dtos.FileDTO">
<id property="fileId" column="file_id"/>
<result property="fileName" column="file_name"/>
<result property="fileUrl" column="file_url"/>
<result property="fileType" column="file_type"/>
<result property="fileSize" column="file_size"/>
</resultMap>
<resultMap id="fileInfoDTO" type="ink.wgink.module.file.pojo.dtos.FileInfoDTO" extends="fileDTO">
<id property="fileId" column="file_id"/>
<result property="fileName" column="file_name"/>
<result property="fileUrl" column="file_url"/>
<result property="fileType" column="file_type"/>
<result property="fileSize" column="file_size"/>
<result property="fileUrl" column="file_url"/>
<result property="filePath" column="file_path"/>
<result property="fileSummary" column="file_summary"/>
<result property="isBack" column="is_back"/>
</resultMap>
<!-- 建表 -->
<update id="createTable">
CREATE TABLE IF NOT EXISTS `sys_file` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`file_id` char(36) NOT NULL,
`file_name` varchar(255) DEFAULT NULL COMMENT '文件名称',
`file_path` varchar(500) DEFAULT NULL COMMENT '文件路径',
`file_url` varchar(500) DEFAULT NULL COMMENT '文件URL',
`file_type` varchar(20) DEFAULT NULL COMMENT '文件类型',
`file_size` varchar(100) DEFAULT NULL COMMENT '文件大小',
`file_summary` varchar(255) DEFAULT NULL COMMENT '文件说明',
`is_back` int(2) DEFAULT '0',
`creator` char(36) DEFAULT NULL COMMENT '创建人',
`gmt_create` datetime DEFAULT NULL COMMENT '创建时间',
`modifier` char(36) DEFAULT NULL COMMENT '修改人',
`gmt_modified` datetime DEFAULT NULL,
`is_delete` int(2) DEFAULT '0',
PRIMARY KEY (`id`,`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
</update>
<!-- 保存文件 -->
<insert id="save" parameterType="map" flushCache="true">
INSERT INTO sys_file(
file_id,
file_name,
file_path,
file_url,
file_type,
file_size,
file_summary,
is_back,
creator,
gmt_create,
modifier,
gmt_modified,
is_delete
) VALUES(
#{fileId},
#{fileName},
#{filePath},
#{fileUrl},
#{fileType},
#{fileSize},
#{fileSummary},
#{isBack},
#{creator},
#{gmtCreate},
#{modifier},
#{gmtModified},
#{isDelete}
)
</insert>
<!-- 删除文件 -->
<update id="remove" parameterType="map" flushCache="true">
UPDATE
sys_file
SET
is_delete = 1,
modifier = #{modifier},
gmt_modified = #{gmtModified}
WHERE
file_id IN
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
#{fileIds[${index}]}
</foreach>
</update>
<!-- 删除文件(物理删除) -->
<delete id="delete" parameterType="map" flushCache="true">
DELETE FROM
sys_file
WHERE
file_id IN
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
#{fileIds[${index}]}
</foreach>
</delete>
<!-- 更新文件描述 -->
<update id="updateSummary" parameterType="map" flushCache="true">
UPDATE
sys_file
SET
file_summary = #{fileSummary}
WHERE
<if test="fileId != null and fileId != ''">
file_id = #{fileId}
</if>
<if test="fileIds != null and fileIds.size > 0">
file_id IN
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
#{fileIds[${index}]}
</foreach>
</if>
</update>
<!-- 获取文件 -->
<select id="getPO" parameterType="map" resultMap="filePO" useCache="true">
SELECT
file_id,
file_name,
file_path,
file_url,
file_type,
file_size,
file_summary,
is_back,
creator,
gmt_create,
modifier,
gmt_modified,
is_delete
FROM
sys_file
WHERE
is_delete = 0
AND
file_id = #{fileId}
</select>
<!-- 文件列表 -->
<select id="list" parameterType="map" resultMap="fileDTO" useCache="true">
SELECT
file_id,
file_name,
file_path,
file_url,
file_type,
file_size,
file_summary,
is_back,
creator,
gmt_create,
modifier,
gmt_modified,
is_delete
FROM
sys_file
WHERE
is_delete = 0
<if test="keywords != null and keywords != ''">
AND
file_name LIKE CONCAT('%', #{keywords}, '%')
</if>
<if test="fileSummary != null and fileSummary != ''">
AND
file_summary = #{fileSummary}
</if>
<if test="startTime != null and startTime != ''">
AND
LEFT(gmt_create, 10) <![CDATA[ >= ]]> #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND
LEFT(gmt_create, 10) <![CDATA[ <= ]]> #{endTime}
</if>
<if test="ids != null and ids.size > 0">
AND
file_id IN
<foreach collection="ids" index="index" open="(" separator="," close=")">
#{ids[${index}]}
</foreach>
</if>
<if test="fileUrl != null and fileUrl != ''">
AND
file_url LIKE concat('%', #{fileUrl}, '%')
</if>
</select>
<!-- 文件列表 -->
<select id="listInfo" parameterType="map" resultMap="fileInfoDTO" useCache="false">
SELECT
file_id,
file_name,
file_path,
file_url,
file_type,
file_size,
file_summary,
is_back,
creator,
gmt_create,
modifier,
gmt_modified,
is_delete
FROM
sys_file
WHERE
is_delete = 0
<if test="keywords != null and keywords != ''">
AND
file_name LIKE CONCAT('%', #{keywords}, '%')
</if>
<if test="startTime != null and startTime != ''">
AND
LEFT(gmt_create, 10) <![CDATA[ >= ]]> #{startTime}
</if>
<if test="endTime != null and endTime != ''">
AND
LEFT(gmt_create, 10) <![CDATA[ <= ]]> #{endTime}
</if>
<if test="fileIds != null and fileIds.size > 0">
AND
file_id IN
<foreach collection="fileIds" index="index" open="(" separator="," close=")">
#{fileIds[${index}]}
</foreach>
</if>
</select>
<!-- 文件列表 -->
<select id="listByMd5" parameterType="java.lang.String" resultMap="fileInfoDTO" useCache="false">
SELECT
file_id,
file_name,
file_path,
file_url,
file_type,
file_size,
file_summary,
is_back,
creator,
gmt_create,
modifier,
gmt_modified,
is_delete
FROM
sys_file
WHERE
is_delete = 0
AND
file_summary = #{_parameter}
</select>
</mapper>

View File

@ -1,8 +1,12 @@
package ink.wgink.module.user.controller.api;
import ink.wgink.annotation.CheckRequestBodyAnnotation;
import ink.wgink.common.base.DefaultBaseController;
import ink.wgink.exceptions.ParamsException;
import ink.wgink.interfaces.consts.IFileConstant;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.module.user.pojo.vos.RestPasswordVO;
import ink.wgink.module.user.pojo.vos.UpdateUsernameVO;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.pojo.result.ErrorResult;
@ -10,15 +14,19 @@ import ink.wgink.pojo.result.SuccessResult;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.module.user.pojo.vos.UserVO;
import ink.wgink.module.user.service.IUserService;
import ink.wgink.pojo.result.UploadExcelResultDTO;
import ink.wgink.util.RegexUtil;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* When you feel like quitting. Think about why you started
@ -85,6 +93,41 @@ public class UserController extends DefaultBaseController {
}
}
@ApiOperation(value = "重置密码", notes = "重置密码接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@PutMapping("resetpassword/{userId}")
@CheckRequestBodyAnnotation
public SuccessResult resetPassword(@PathVariable("userId") String userId, @RequestBody RestPasswordVO restPasswordVO) {
userService.resetPassword(userId, restPasswordVO);
return new SuccessResult();
}
@ApiOperation(value = "修改用户名", notes = "修改用户名密码接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@PutMapping("updateusername/{userId}")
@CheckRequestBodyAnnotation
public SuccessResult updateUsername(@PathVariable("userId") String userId, @RequestBody UpdateUsernameVO updateUsernameVO) throws Exception {
userService.updateUsername(userId, updateUsernameVO);
return new SuccessResult();
}
@ApiOperation(value = "导入Excel", notes = "导入Excel接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "excel", value = "文件名称", paramType = "query"),
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@PostMapping("importexcel")
public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
if (Objects.isNull(excel)) {
throw new ParamsException("Excel不能为空");
}
if (!excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLS) &&
!excel.getOriginalFilename().endsWith(IFileConstant.EXCEL_SUFFIX_XLSX)) {
throw new ParamsException("文件格式为Excel");
}
return userService.importExcel(excel);
}
@ApiOperation(value = "用户列表", notes = "用户列表接口")
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("list")
@ -109,4 +152,14 @@ public class UserController extends DefaultBaseController {
return userService.listPage(page);
}
@ApiOperation(value = "用户详情", notes = "用户详情接口")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId", value = "用户ID", paramType = "path")
})
@ApiResponses({@ApiResponse(code = 400, message = "请求失败", response = ErrorResult.class)})
@GetMapping("get/{userId}")
public UserDTO getUser(@PathVariable("userId") String userId) {
return userService.get(userId);
}
}

View File

@ -0,0 +1,72 @@
package ink.wgink.module.user.controller.route;
import ink.wgink.interfaces.consts.ISystemConstant;
import ink.wgink.util.ResourceUtil;
import ink.wgink.util.request.RequestUtil;
import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: UserRouteController
* @Description: 用户路由
* @Author: wanggeng
* @Date: 2021/2/5 7:50 下午
* @Version: 1.0
*/
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "用户路由接口")
@Controller
@RequestMapping(ISystemConstant.ROUTE_PREFIX + "/user")
public class UserRouteController {
@GetMapping("list")
public ModelAndView list() {
return new ModelAndView("user/list");
}
@GetMapping("save")
public ModelAndView save() {
return new ModelAndView("user/save");
}
@GetMapping("update")
public ModelAndView update() {
return new ModelAndView("user/update");
}
@GetMapping("rest-password")
public ModelAndView restPassword() {
return new ModelAndView("user/rest-password");
}
@GetMapping("update-username")
public ModelAndView updateUsername() {
return new ModelAndView("user/update-username");
}
@GetMapping("update-password")
public ModelAndView updatePassword() {
return new ModelAndView("user/update-password");
}
@GetMapping("upload/upload-excel")
public ModelAndView uploadExcel() {
return new ModelAndView("user/upload/upload-excel");
}
@GetMapping("upload/upload-excel-template")
public void excelTemplate(HttpServletResponse response) throws IOException {
File template = ResourceUtil.getResourceFile("templates/user/upload/upload-excel-template.xls");
RequestUtil.download(response, template, "用户导入模板.xls");
}
}

View File

@ -24,6 +24,13 @@ import java.util.Map;
@Repository
public interface IUserDao {
/**
* 建表
*
* @throws UpdateException
*/
void createTable() throws UpdateException;
/**
* 新增
*

View File

@ -0,0 +1,72 @@
package ink.wgink.module.user.excel;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: UserExcel
* @Description: 用户Excel
* @Author: WangGeng
* @Date: 2020/1/6 11:11 下午
* @Version: 1.0
**/
public class UserExcel {
@ExcelProperty(index = 0)
private String userUsername;
@ExcelProperty(index = 1)
private String userName;
@ExcelProperty(index = 2)
private String userPhone;
@ExcelProperty(index = 3)
private String userEmail;
public String getUserUsername() {
return userUsername == null ? "" : userUsername.trim().replaceAll("\\s", "");
}
public void setUserUsername(String userUsername) {
this.userUsername = userUsername;
}
public String getUserName() {
return userName == null ? "" : userName.trim().replaceAll("\\s", "");
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPhone() {
return userPhone == null ? "" : userPhone.trim().replaceAll("\\s", "");
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
public String getUserEmail() {
return userEmail == null ? "" : userEmail.trim().replaceAll("\\s", "");
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"userUsername\":")
.append("\"").append(userUsername).append("\"");
sb.append(",\"userName\":")
.append("\"").append(userName).append("\"");
sb.append(",\"userPhone\":")
.append("\"").append(userPhone).append("\"");
sb.append(",\"userEmail\":")
.append("\"").append(userEmail).append("\"");
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,84 @@
package ink.wgink.module.user.excel;
import com.alibaba.excel.annotation.ExcelProperty;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: UserExcelError
* @Description: 人员Excel异常
* @Author: WangGeng
* @Date: 2020/1/7 12:28 下午
* @Version: 1.0
**/
public class UserExcelError {
@ExcelProperty(index = 0)
private String userUsername;
@ExcelProperty(index = 1)
private String userName;
@ExcelProperty(index = 2)
private String userPhone;
@ExcelProperty(index = 3)
private String userEmail;
@ExcelProperty(index = 4)
private String reason;
public String getUserUsername() {
return userUsername == null ? "" : userUsername.trim();
}
public void setUserUsername(String userUsername) {
this.userUsername = userUsername;
}
public String getUserName() {
return userName == null ? "" : userName.trim();
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPhone() {
return userPhone == null ? "" : userPhone.trim();
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
public String getUserEmail() {
return userEmail == null ? "" : userEmail.trim();
}
public void setUserEmail(String userEmail) {
this.userEmail = userEmail;
}
public String getReason() {
return reason == null ? "" : reason.trim();
}
public void setReason(String reason) {
this.reason = reason;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"userUsername\":")
.append("\"").append(userUsername).append("\"");
sb.append(",\"userName\":")
.append("\"").append(userName).append("\"");
sb.append(",\"userPhone\":")
.append("\"").append(userPhone).append("\"");
sb.append(",\"userEmail\":")
.append("\"").append(userEmail).append("\"");
sb.append(",\"reason\":")
.append("\"").append(reason).append("\"");
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,48 @@
package ink.wgink.module.user.excel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: UserExcelListener
* @Description: 用户Excel监听器
* @Author: WangGeng
* @Date: 2020/1/6 11:06 下午
* @Version: 1.0
**/
public abstract class UserExcelListener extends AnalysisEventListener<UserExcel> {
private static final Logger LOG = LoggerFactory.getLogger(UserExcelListener.class);
private List<UserExcel> userExcels = new ArrayList<>(0);
@Override
public void invoke(UserExcel userExcel, AnalysisContext analysisContext) {
userExcels.add(userExcel);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
try {
listUserExcel(userExcels);
} catch (Exception e) {
LOG.error(e.getMessage());
}
userExcels.clear();
}
/**
* 获取用户列表
*
* @param userExcels
*/
public abstract void listUserExcel(List<UserExcel> userExcels) throws Exception;
}

View File

@ -0,0 +1,40 @@
package ink.wgink.module.user.pojo.vos;
import ink.wgink.annotation.CheckEmptyAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: UpdateUserUsernameVO
* @Description: 修改用户名
* @Author: WangGeng
* @Date: 2020/5/21 10:04 下午
* @Version: 1.0
**/
@ApiModel
public class RestPasswordVO {
@ApiModelProperty(name = "updateReason", value = "修改原因")
@CheckEmptyAnnotation(name = "修改原因")
private String updateReason;
public String getUpdateReason() {
return updateReason == null ? "" : updateReason.trim();
}
public void setUpdateReason(String updateReason) {
this.updateReason = updateReason;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"updateReason\":\"")
.append(updateReason).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,53 @@
package ink.wgink.module.user.pojo.vos;
import ink.wgink.annotation.CheckEmptyAnnotation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: UpdateUserUsernameVO
* @Description: 修改用户名
* @Author: WangGeng
* @Date: 2020/5/21 10:04 下午
* @Version: 1.0
**/
@ApiModel
public class UpdateUsernameVO {
@ApiModelProperty(name = "username", value = "用户名")
@CheckEmptyAnnotation(name = "用户名", regex = "username")
private String username;
@ApiModelProperty(name = "updateReason", value = "修改原因")
@CheckEmptyAnnotation(name = "修改原因")
private String updateReason;
public String getUsername() {
return username == null ? "" : username.trim();
}
public void setUsername(String username) {
this.username = username;
}
public String getUpdateReason() {
return updateReason == null ? "" : updateReason.trim();
}
public void setUpdateReason(String updateReason) {
this.updateReason = updateReason;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"username\":\"")
.append(username).append('\"');
sb.append(",\"updateReason\":\"")
.append(updateReason).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -1,9 +1,14 @@
package ink.wgink.module.user.service;
import ink.wgink.interfaces.user.IUserBaseService;
import ink.wgink.module.user.pojo.vos.RestPasswordVO;
import ink.wgink.module.user.pojo.vos.UpdateUsernameVO;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.module.user.pojo.vos.UserVO;
import ink.wgink.pojo.result.UploadExcelResultDTO;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@ -46,17 +51,36 @@ public interface IUserService extends IUserBaseService {
/**
* 修改用户
*
* @param userId
* @param userVO
* @param userId 用户ID
* @param userVO 用户内容
* @return
*/
void update(String userId, UserVO userVO);
/**
* 用户列表
* 重置用户密码
*
* @param params
* @param userId 用户ID
* @param restPasswordVO 重置密码
* @return
*/
List<UserDTO> list(Map<String, Object> params);
void resetPassword(String userId, RestPasswordVO restPasswordVO);
/**
* 修改用户名
*
* @param userId 用户ID
* @param updateUsernameVO 更新用户名
*/
void updateUsername(String userId, UpdateUsernameVO updateUsernameVO);
/**
* 导入Excel
*
* @param excel
* @return
* @throws IOException
*/
UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException;
}

View File

@ -1,23 +1,36 @@
package ink.wgink.module.user.service.impl;
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ink.wgink.common.base.DefaultBaseService;
import ink.wgink.exceptions.SearchException;
import ink.wgink.module.file.excel.error.AbstractErrorExcelHandler;
import ink.wgink.module.file.service.IFileService;
import ink.wgink.module.user.dao.IUserDao;
import ink.wgink.module.user.excel.UserExcel;
import ink.wgink.module.user.excel.UserExcelError;
import ink.wgink.module.user.excel.UserExcelListener;
import ink.wgink.module.user.pojo.vos.RestPasswordVO;
import ink.wgink.module.user.pojo.vos.UpdateUsernameVO;
import ink.wgink.module.user.pojo.vos.UserVO;
import ink.wgink.module.user.service.IUserService;
import ink.wgink.pojo.ListPage;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.pojo.result.SuccessResultList;
import ink.wgink.module.user.dao.IUserDao;
import ink.wgink.module.user.pojo.vos.UserVO;
import ink.wgink.module.user.service.IUserService;
import ink.wgink.pojo.result.UploadExcelResultDTO;
import ink.wgink.util.UUIDUtil;
import ink.wgink.util.map.HashMapUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -38,9 +51,13 @@ public class UserServiceImpl extends DefaultBaseService implements IUserService
private IUserDao userDao;
@Autowired
private PasswordEncoder passwordEncoder;
@Value("${user.default-password:88888888}")
private String defaultPassword;
@Autowired
private IFileService fileService;
@Override
public synchronized void save(UserVO userVO) {
public void save(UserVO userVO) {
saveUser(userVO, false);
}
@ -56,7 +73,7 @@ public class UserServiceImpl extends DefaultBaseService implements IUserService
* @param isRegister 是否注册
*/
private void saveUser(UserVO userVO, boolean isRegister) {
UserDTO userDTO = get(userVO.getUserUsername());
UserDTO userDTO = getByUsername(userVO.getUserUsername());
if (userDTO != null) {
throw new SearchException("用户已经存在");
}
@ -75,7 +92,7 @@ public class UserServiceImpl extends DefaultBaseService implements IUserService
@Override
public void remove(List<String> ids) {
Map<String, Object> params = getHashMap(2);
params.put("ids", ids);
params.put("userIds", ids);
setUpdateInfo(params);
userDao.remove(params);
}
@ -87,9 +104,88 @@ public class UserServiceImpl extends DefaultBaseService implements IUserService
}
Map<String, Object> params = HashMapUtil.beanToMap(userVO);
setUpdateInfo(params);
params.put("userId", userId);
userDao.update(params);
}
@Override
public void resetPassword(String userId, RestPasswordVO restPasswordVO) {
UserDTO userDTO = get(userId);
if (userDTO == null) {
throw new SearchException("修改用户不存在");
}
Map<String, Object> params = getHashMap(4);
params.put("userId", userId);
params.put("userPassword", passwordEncoder.encode(DigestUtils.md5Hex(DigestUtils.md5Hex(DigestUtils.md5Hex(defaultPassword)))));
userDao.updatePassword(params);
}
@Override
public void updateUsername(String userId, UpdateUsernameVO updateUsernameVO) {
UserDTO oldUserDTO = get(userId);
if (oldUserDTO == null) {
throw new SearchException("用户不存在");
}
Map<String, Object> params = getHashMap(2);
params.put("userUsername", updateUsernameVO.getUsername());
UserDTO userDTO = userDao.get(params);
if (userDTO != null && !StringUtils.equals(userId, userDTO.getUserId())) {
throw new SearchException("新用户名已经存在");
}
params.put("userId", userId);
userDao.updateUsername(params);
}
@Override
public UploadExcelResultDTO importExcel(MultipartFile excel) throws IOException {
Map<String, Object> params = getHashMap(16);
// 错误列表
List<UserExcelError> userExcelErrors = new ArrayList<>();
long startTime = System.currentTimeMillis();
LOG.debug("读取Excel");
EasyExcel.read(excel.getInputStream(), UserExcel.class, new UserExcelListener() {
@Override
public void listUserExcel(List<UserExcel> userExcels) throws Exception {
for (UserExcel userExcel : userExcels) {
// 判断昵称存在
String userUsername = userExcel.getUserUsername();
String userName = userExcel.getUserName();
if (StringUtils.isBlank(userUsername) || StringUtils.isBlank(userName)) {
userExcelErrors.add(getUserExcelError(userExcel, "必填值存在空值,导入失败"));
continue;
}
String userPhone = userExcel.getUserPhone();
String userEmail = userExcel.getUserEmail();
try {
// 保存用户
UserVO userVO = new UserVO();
userVO.setUserUsername(userUsername);
userVO.setUserName(userName);
userVO.setUserPassword(defaultPassword);
userVO.setUserPhone(userPhone);
userVO.setUserEmail(userEmail);
userVO.setUserType(2);
userVO.setUserState(0);
saveUser(userVO, false);
} catch (Exception e) {
userExcelErrors.add(getUserExcelError(userExcel, e.getMessage()));
}
}
}
}).headRowNumber(2).sheet().doRead();
long endTime = System.currentTimeMillis();
String excelFileId = null;
if (userExcelErrors.size() > 0) {
excelFileId = new AbstractErrorExcelHandler<UserExcelError>(fileService) {
@Override
public List<List<String>> excelHeaderNames() {
return simpleExcelHeader(new String[]{"用户名", "昵称", "手机", "邮箱", "错误原因"});
}
}.saveErrorExcel(userExcelErrors);
}
return new UploadExcelResultDTO(userExcelErrors.size(), endTime - startTime, excelFileId);
}
@Override
public UserDTO get(String userId) {
Map<String, Object> params = getHashMap(2);
@ -111,6 +207,13 @@ public class UserServiceImpl extends DefaultBaseService implements IUserService
return list(params);
}
@Override
public List<UserDTO> listByUsernames(List<String> usernames) {
Map<String, Object> params = getHashMap(2);
params.put("userUsernames", usernames);
return list(params);
}
@Override
public List<UserDTO> list(Map<String, Object> params) {
return userDao.list(params);
@ -124,4 +227,21 @@ public class UserServiceImpl extends DefaultBaseService implements IUserService
return new SuccessResultList<>(userDTOs, pageInfo.getPageNum(), pageInfo.getTotal());
}
/**
* Excel导入错误对象
*
* @param userExcel
* @param reason
* @return
*/
private UserExcelError getUserExcelError(UserExcel userExcel, String reason) {
UserExcelError userExcelError = new UserExcelError();
userExcelError.setUserUsername(userExcel.getUserUsername());
userExcelError.setUserName(userExcel.getUserName());
userExcelError.setUserPhone(userExcel.getUserPhone());
userExcelError.setUserEmail(userExcel.getUserEmail());
userExcelError.setReason(reason);
return userExcelError;
}
}

View File

@ -0,0 +1,62 @@
package ink.wgink.module.user.startup;
import ink.wgink.module.user.dao.IUserDao;
import ink.wgink.pojo.dtos.user.UserDTO;
import ink.wgink.util.date.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ServiceUserStartUp
* @Description: 用户业务
* @Author: wanggeng
* @Date: 2021/2/5 8:59 下午
* @Version: 1.0
*/
@Component
public class ServiceUserStartUp implements ApplicationRunner {
private static final Logger LOG = LoggerFactory.getLogger(ServiceUserStartUp.class);
@Autowired
private IUserDao userDao;
@Override
public void run(ApplicationArguments args) throws Exception {
initTable();
}
/**
* 建表
*/
private void initTable() {
LOG.debug("创建 sys_user 表");
userDao.createTable();
LOG.debug("检查 admin 是否存在");
Map<String, Object> params = new HashMap<>(2);
params.put("userUsername", "admin");
UserDTO userDTO = userDao.get(params);
if (userDTO == null) {
LOG.debug("admin 不存在,新增");
String currentDate = DateUtil.getTime();
params.put("userId", "1");
params.put("userPassword", "");
params.put("userName", "超级管理员");
params.put("gmtCreate", currentDate);
params.put("creator", "1");
params.put("gmtModified", currentDate);
params.put("modifier", "1");
params.put("isDelete", 0);
userDao.save(params);
}
}
}

View File

@ -45,6 +45,43 @@
<result property="gmtCreate" column="gmt_create"/>
</resultMap>
<update id="createTable">
CREATE TABLE IF NOT EXISTS `sys_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` char(36) NOT NULL,
`user_username` varchar(255) NOT NULL COMMENT '用户名',
`user_password` varchar(255) DEFAULT NULL COMMENT '密码',
`user_name` varchar(255) DEFAULT NULL COMMENT '姓名',
`user_phone` varchar(20) DEFAULT NULL COMMENT '电话',
`user_email` varchar(255) DEFAULT NULL COMMENT '邮箱',
`user_ukey` varchar(32) DEFAULT NULL COMMENT 'UKey',
`user_ukey_electronic_secret_key` text COMMENT '用户UKey电子秘钥',
`user_type` int(2) DEFAULT '2',
`user_state` int(2) DEFAULT '0' COMMENT '用户状态',
`user_avatar` char(36) DEFAULT NULL COMMENT '头像',
`user_longitude` varchar(255) DEFAULT '0' COMMENT '经度',
`user_latitude` varchar(255) DEFAULT '0' COMMENT '纬度',
`last_login_address` varchar(255) DEFAULT NULL COMMENT '最后登录地址',
`last_login_time` datetime DEFAULT NULL COMMENT '最后登录时间',
`login_type` int(1) DEFAULT '1' COMMENT '登录类型',
`gmt_password_modified` date DEFAULT NULL COMMENT '密码修改时间',
`remarks` varchar(255) DEFAULT NULL COMMENT '备注',
`creator` char(36) DEFAULT NULL,
`gmt_create` datetime DEFAULT NULL,
`modifier` char(36) DEFAULT NULL,
`gmt_modified` datetime DEFAULT NULL,
`is_delete` int(2) DEFAULT '0',
PRIMARY KEY (`id`,`user_id`,`user_username`),
UNIQUE KEY `user_username` (`user_username`) USING BTREE,
KEY `user_id` (`user_id`) USING BTREE,
KEY `user_name` (`user_name`) USING BTREE,
KEY `user_id_2` (`user_id`,`user_username`,`user_name`) USING BTREE,
KEY `user_id_3` (`user_id`,`user_name`) USING BTREE,
KEY `user_id_4` (`user_id`,`user_name`,`user_avatar`) USING BTREE,
KEY `is_delete_idx` (`is_delete`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
</update>
<!-- 保存用户 -->
<insert id="save" parameterType="map" flushCache="true">
INSERT INTO sys_user(

View File

@ -0,0 +1,349 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/js/vendor/viewer/viewer.min.css">
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-fluid layui-anim layui-anim-fadein">
<div class="layui-row layui-col-space15">
<div class="layui-col-md12">
<div class="layui-card">
<div class="layui-card-body">
<div class="test-table-reload-btn" style="margin-bottom: 10px;">
<div class="layui-inline">
<input type="text" id="keywords" class="layui-input search-item" placeholder="输入关键字">
</div>
<div class="layui-inline">
<input type="text" id="startTime" class="layui-input search-item" placeholder="开始时间" readonly>
</div>
<div class="layui-inline">
<input type="text" id="endTime" class="layui-input search-item" placeholder="结束时间" readonly>
</div>
<button type="button" id="search" class="layui-btn layui-btn-sm">
<i class="fa fa-lg fa-search"></i> 搜索
</button>
<button type="button" class="layui-btn layui-btn-sm" id="uploadExcel" style="margin-left: 0;">
<i class="fa fa-lg fa-cloud-upload"></i> 导入数据
</button>
</div>
<table class="layui-hide" id="dataTable" lay-filter="dataTable"></table>
<!-- 表头按钮组 -->
<script type="text/html" id="headerToolBar">
<div class="layui-btn-group">
<button type="button" class="layui-btn layui-btn-sm" lay-event="saveEvent">
<i class="fa fa-lg fa-plus"></i> 新增
</button>
<button type="button" class="layui-btn layui-btn-normal layui-btn-sm" lay-event="updateEvent">
<i class="fa fa-lg fa-edit"></i> 编辑
</button>
<button type="button" class="layui-btn layui-btn-danger layui-btn-sm" lay-event="removeEvent">
<i class="fa fa-lg fa-trash"></i> 删除
</button>
</div>
</script>
</div>
</div>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/'
}).extend({
index: 'lib/index'
}).use(['index', 'table', 'laydate', 'upload'], function() {
var $ = layui.$;
var $win = $(window);
var table = layui.table;
var admin = layui.admin;
var layer = layui.layer;
var laydate = layui.laydate;
var windowWidth = $(window).width();
var windowHeight = $(window).height();
var resizeTimeout = null;
var tableUrl = 'api/user/listpage';
// 初始化表格
function initTable() {
table.render({
elem: '#dataTable',
id: 'dataTable',
url: top.restAjax.path(tableUrl, []),
width: admin.screen() > 1 ? '100%' : '',
height: $win.height() - 90,
limit: 20,
limits: [20, 40, 60, 80, 100, 200],
toolbar: '#headerToolBar',
request: {
pageName: 'page',
limitName: 'rows'
},
cols: [
[
{type:'checkbox', fixed: 'left'},
{field:'rowNum', width:80, title: '序号', fixed: 'left', align:'center', templet: '<span>{{d.LAY_INDEX}}</span>'},
{field:'userUsername', width:140, title: '用户名', sort: true, align:'center',
templet: function(rowData) {
return '<a href="javascript:void(0);" lay-event="userUsernameEvent">'+ rowData.userUsername +'</a>';
}
},
{field:'userName', width:140, title: '昵称', sort: true, align:'center'},
{field:'userType', width:100, title: '类型', sort: true, align:'center',
templet: function(item) {
if(item.userType == 1) {
return '<span class="layui-badge layui-bg-green">系统用户</span>';
} else if(item.userType == 2) {
return '<span class="layui-badge layui-bg-orange">普通用户</span>';
}
return '<span class="layui-badge">类型错误</span>';
}
},
{field:'userState', width:80, title: '状态', sort: true, align:'center',
templet: function(item) {
var value;
switch (item.userState) {
case 1:
value = '<span class="layui-badge">冻结</span>';
break;
case 2:
value = '<span class="layui-badge layui-bg-green">锁定</span>';
break;
default:
value = '<span class="layui-badge layui-bg-blue">正常</span>';
}
return value;
}
},
{field:'userPhone', width:140, title: '手机', sort: true, align:'center',
templet: function(item) {
if(!item.userPhone) {
return '-';
}
return item.userPhone;
}
},
{field:'userEmail', width: 160, title: '邮箱', sort: true, align:'center',
templet: function(item) {
if(!item.userEmail) {
return '-';
}
return item.userEmail;
}
},
{field:'lastLoginAddress', width:140, title: '登录地址', align:'center',
templet: function(item) {
if(!item.lastLoginAddress) {
return '-';
}
return item.lastLoginAddress;
}
},
{field:'lastLoginTime', width:200, title: '最后登录系统时间', align:'center',
templet: function(item) {
if(!item.lastLoginTime) {
return '-';
}
return item.lastLoginTime;
}
},
{field:'gmtCreate', width:200, title: '创建时间', align:'center',
templet: function(item) {
if(!item.gmtCreate) {
return '-';
}
return item.gmtCreate;
}
},
{field:'opition', width:120, title: '操作', fixed:'right', align:'center',
templet: function(item) {
return '<button type="button" class="layui-btn layui-btn-sm" lay-event="resetPasswordEvent">' +
'<i class="fa fa-key"></i> 重置密码' +
'</button>';
}
},
]
],
page: true,
parseData: function(data) {
return {
'code': 0,
'msg': '',
'count': data.total,
'data': data.rows
};
}
});
}
// 重载表格
function reloadTable(currentPage) {
table.reload('dataTable', {
url: top.restAjax.path(tableUrl, []),
where: {
keywords: $('#keywords').val(),
startTime: $('#startTime').val(),
endTime: $('#endTime').val()
},
page: {
curr: currentPage
},
height: $win.height() - 90,
});
}
// 初始化日期
function initDate() {
// 日期选择
laydate.render({
elem: '#startTime',
format: 'yyyy-MM-dd'
});
laydate.render({
elem: '#endTime',
format: 'yyyy-MM-dd'
});
}
// 删除
function removeData(ids) {
top.dialog.msg(top.dataMessage.delete, {
time: 0,
btn: [top.dataMessage.button.yes, top.dataMessage.button.no],
shade: 0.3,
yes: function (index) {
top.dialog.close(index);
var layIndex;
top.restAjax.delete(top.restAjax.path('api/user/remove/{ids}', [ids]), {}, null, function (code, data) {
top.dialog.msg(top.dataMessage.deleteSuccess, {time: 1000});
reloadTable();
}, function (code, data) {
top.dialog.msg(data.msg);
}, function () {
layIndex = top.dialog.msg(top.dataMessage.deleting, {icon: 16, time: 0, shade: 0.3});
}, function () {
top.dialog.close(layIndex);
});
}
});
}
initTable();
initDate();
// 事件 - 页面变化
$win.on('resize', function() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function() {
reloadTable();
}, 500);
});
// 事件 - 搜索
$(document).on('click', '#search', function() {
reloadTable(1);
});
$(document).on('click', '#uploadExcel', function() {
top.dialog.open({
url: top.restAjax.path('route/user/upload/upload-excel', []),
title: '导入用户数据',
width: '300px',
height: '196px',
onClose: function() {
reloadTable();
}
});
});
// 事件 - 增删改
table.on('toolbar(dataTable)', function(obj) {
var layEvent = obj.event;
var checkStatus = table.checkStatus('dataTable');
var checkDatas = checkStatus.data;
if(layEvent === 'saveEvent') {
layer.open({
type: 2,
title: false,
closeBtn: 0,
area: ['100%', '100%'],
shadeClose: true,
anim: 2,
content: top.restAjax.path('route/user/save', []),
end: function() {
reloadTable();
}
});
} else if(layEvent === 'updateEvent') {
if(checkDatas.length === 0) {
top.dialog.msg(top.dataMessage.table.selectEdit);
} else if(checkDatas.length > 1) {
top.dialog.msg(top.dataMessage.table.selectOneEdit);
} else {
layer.open({
type: 2,
title: false,
closeBtn: 0,
area: ['100%', '100%'],
shadeClose: true,
anim: 2,
content: top.restAjax.path('route/user/update?userId={id}', [checkDatas[0].userId]),
end: function() {
reloadTable();
}
});
}
} else if(layEvent === 'removeEvent') {
if(checkDatas.length === 0) {
top.dialog.msg(top.dataMessage.table.selectDelete);
} else {
var ids = '';
for(var i = 0, item; item = checkDatas[i++];) {
if(i > 1) {
ids += '_';
}
ids += item.userId;
}
removeData(ids);
}
}
});
table.on('tool(dataTable)', function(obj) {
var layEvent = obj.event;
var data = obj.data;
if(layEvent === 'userUsernameEvent') {
top.dialog.open({
url: top.restAjax.path('route/user/update-username?userId={userId}', [data.userId]),
title: '【'+ data.userName +'】修改用户名',
width: '320px',
height: '330px',
onClose: function() {
reloadTable();
}
});
} else if(layEvent === 'resetPasswordEvent') {
top.dialog.open({
url: top.restAjax.path('route/user/rest-password?userId={userId}', [data.userId]),
title: '【'+ data.userName +'】重置密码',
width: '320px',
height: '280px',
onClose: function() {
reloadTable();
}
});
}
});
// 事件-排序
table.on('sort(dataTable)', function(obj) {
table.reload('dataTable', {
initSort: obj,
where: {
sort: obj.field,
order: obj.type
}
});
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,86 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-fluid layui-anim layui-anim-fadein" style="padding: 0;overflow: hidden;">
<div class="layui-card">
<div class="layui-card-body" style="padding: 15px;">
<form class="layui-form layui-form-pane" lay-filter="dataForm">
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">修改原因</label>
<div class="layui-input-block">
<textarea name="updateReason" required lay-verify="required" placeholder="请输入修改原因" class="layui-textarea" maxlength="80"></textarea>
</div>
</div>
<div class="layui-form-item layui-layout-admin">
<div class="layui-input-block">
<div class="layui-footer" style="left: 0;">
<button type="button" class="layui-btn" lay-submit lay-filter="submitForm">提交编辑</button>
<button type="button" class="layui-btn layui-btn-primary close">关闭窗口</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form'], function(){
var $ = layui.$;
var form = layui.form;
var userId = top.restAjax.params(window.location.href).userId;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
// 提交表单
form.on('submit(submitForm)', function(formData) {
top.dialog.confirm(top.dataMessage.update, function(index) {
top.dialog.close(index);
var loadLayerIndex;
top.restAjax.put(top.restAjax.path('api/user/resetpassword/{userId}', [userId]), formData.field, null, function(code, data) {
var layerIndex = top.dialog.msg(top.dataMessage.updateSuccess, {
time: 0,
btn: [top.dataMessage.button.yes, top.dataMessage.button.no],
shade: 0.3,
yes: function(index) {
top.dialog.close(index);
window.location.reload();
},
btn2: function() {
closeBox();
}
});
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.updating, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
});
return false;
});
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,169 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-fluid layui-anim layui-anim-fadein">
<div class="layui-card">
<div class="layui-card-header">
<span class="layui-breadcrumb" lay-filter="breadcrumb" style="visibility: visible;">
<a class="close" href="javascript:void(0);">上级列表</a><span lay-separator="">/</span>
<a href="javascript:void(0);"><cite>新增内容</cite></a>
</span>
</div>
<div class="layui-card-body" style="padding: 15px;">
<form class="layui-form layui-form-pane" lay-filter="dataForm">
<div class="layui-row">
<div class="layui-form-item">
<label class="layui-form-label">用户名 *</label>
<div class="layui-input-block">
<input type="text" name="userUsername" lay-verify="userUsername" placeholder="请输入用户名" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">密码 *</label>
<div class="layui-input-block">
<input type="password" name="userPassword" lay-verify="required" placeholder="请输入密码" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">昵称 *</label>
<div class="layui-input-block">
<input type="text" name="userName" lay-verify="required" placeholder="请输入昵称" class="layui-input">
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">类型 *</label>
<div class="layui-input-block">
<input type="radio" name="userType" value="1" title="系统用户">
<input type="radio" name="userType" value="2" title="普通用户" checked>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态 *</label>
<div class="layui-input-block">
<select name="userState" lay-verify="required">
<option value="0">正常</option>
<option value="1">冻结</option>
<option value="2">锁定</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手机</label>
<div class="layui-input-block">
<input type="number" name="userPhone" placeholder="请输入手机" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">邮箱</label>
<div class="layui-input-block">
<input type="text" name="userEmail" placeholder="请输入邮箱" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">头像</label>
<div class="layui-input-block">
<div class="layui-textarea">
<img id="avatarImage" src="assets/images/profile-photo.jpg" title="点击修改头像">
<input type="hidden" id="userAvatar" name="userAvatar">
</div>
</div>
</div>
</div>
<div class="layui-form-item layui-layout-admin">
<div class="layui-input-block">
<div class="layui-footer" style="left: 0;">
<button type="button" class="layui-btn" lay-submit lay-filter="submitForm">提交新增</button>
<button type="button" class="layui-btn layui-btn-primary close">返回上级</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form', 'laydate'], function(){
var $ = layui.$;
var form = layui.form;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
// 提交表单
form.on('submit(submitForm)', function(formData) {
var authorizedGrantTypes = top.restAjax.checkBoxToString(formData.field, 'authorizedGrantTypes');
formData.field.authorizedGrantTypes = authorizedGrantTypes;
top.dialog.confirm(top.dataMessage.commit, function(index) {
top.dialog.close(index);
var loadLayerIndex;
top.restAjax.post(top.restAjax.path('api/user/save', []), formData.field, null, function(code, data) {
var layerIndex = top.dialog.msg(top.dataMessage.commitSuccess, {
time: 0,
btn: [top.dataMessage.button.yes, top.dataMessage.button.no],
shade: 0.3,
yes: function(index) {
top.dialog.close(index);
window.location.reload();
},
btn2: function() {
closeBox();
}
});
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.committing, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
});
return false;
});
form.verify({
userUsername: function(value, item) {
if(!new RegExp('^[a-zA-Z0-9_\\s·]+$').test(value)) {
return '用户名不能有特殊字符';
}
if(/(^\_)|(\__)|(\_+$)/.test(value)){
return '用户名首尾不能出现下划线\'_\'';
}
}
});
$('#avatarImage').on('click', function() {
top.dialog.open({
url: 'route/file/uploadimage/v2?fileId='+ $('#userAvatar').val(),
title: '上传头像',
width: '800px',
height: '470px',
onClose: function() {
var uploadImage = top.dialog.dialogData.uploadImage;
if(typeof(uploadImage) != 'undefined' && null != uploadImage && '' != uploadImage) {
$('#avatarImage').attr('src', 'route/file/downloadfile/false/' + uploadImage);
$('#userAvatar').val(uploadImage);
}
}
})
});
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,104 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-fluid layui-anim layui-anim-fadein" style="padding: 0;overflow: hidden;">
<div class="layui-card">
<div class="layui-card-body" style="padding: 15px;">
<form class="layui-form layui-form-pane" lay-filter="dataForm">
<div class="layui-form-item">
<label class="layui-form-label">旧密码</label>
<div class="layui-input-block">
<input type="password" name="oldPassword" lay-verify="required" placeholder="请输入旧密码" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" id="newPassword" name="newPassword" lay-verify="required" placeholder="请输入新密码" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" name="confirmNewPassword" lay-verify="required|passwordSame" placeholder="请输入确认密码" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-layout-admin">
<div class="layui-input-block">
<div class="layui-footer" style="left: 0;">
<button type="button" class="layui-btn" lay-submit lay-filter="submitForm">提交编辑</button>
<button type="button" class="layui-btn layui-btn-primary close">关闭窗口</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form'], function(){
var $ = layui.$;
var form = layui.form;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
// 提交表单
form.on('submit(submitForm)', function(formData) {
top.dialog.confirm(top.dataMessage.commit, function(index) {
top.dialog.close(index);
var loadLayerIndex;
top.restAjax.put(top.restAjax.path('api/user/updateuserpassword', []), formData.field, null, function(code, data) {
var layerIndex = top.dialog.msg(top.dataMessage.commitSuccess, {
time: 0,
btn: [top.dataMessage.button.yes, top.dataMessage.button.no],
shade: 0.3,
yes: function(index) {
top.dialog.close(index);
window.location.reload();
},
btn2: function() {
closeBox();
}
});
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.committing, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
});
return false;
});
form.verify({
passwordSame: function(value, item) {
if($('#newPassword').val() != value) {
return '确认密码不一致';
}
},
});
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,102 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-fluid layui-anim layui-anim-fadein" style="padding: 0;overflow: hidden;">
<div class="layui-card">
<div class="layui-card-body" style="padding: 15px;">
<form class="layui-form layui-form-pane" lay-filter="dataForm">
<div class="layui-form-item">
<label class="layui-form-label">新用户名</label>
<div class="layui-input-block">
<input type="username" name="username" lay-verify="username" placeholder="请输入新用户名" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">修改原因</label>
<div class="layui-input-block">
<textarea name="updateReason" required lay-verify="required" placeholder="请输入修改原因" class="layui-textarea" maxlength="80"></textarea>
</div>
</div>
<div class="layui-form-item layui-layout-admin">
<div class="layui-input-block">
<div class="layui-footer" style="left: 0;">
<button type="button" class="layui-btn" lay-submit lay-filter="submitForm">提交编辑</button>
<button type="button" class="layui-btn layui-btn-primary close">关闭窗口</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form'], function(){
var $ = layui.$;
var form = layui.form;
var userId = top.restAjax.params(window.location.href).userId;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
// 提交表单
form.on('submit(submitForm)', function(formData) {
top.dialog.confirm(top.dataMessage.update, function(index) {
top.dialog.close(index);
var loadLayerIndex;
top.restAjax.put(top.restAjax.path('api/user/updateusername/{userId}', [userId]), formData.field, null, function(code, data) {
var layerIndex = top.dialog.msg(top.dataMessage.updateSuccess, {
time: 0,
btn: [top.dataMessage.button.yes, top.dataMessage.button.no],
shade: 0.3,
yes: function(index) {
top.dialog.close(index);
window.location.reload();
},
btn2: function() {
closeBox();
}
});
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.updating, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
});
return false;
});
form.verify({
userUsername: function(value, item) {
if(!new RegExp('^[a-zA-Z0-9_\\s·]+$').test(value)) {
return '用户名不能有特殊字符';
}
if(/(^\_)|(\__)|(\_+$)/.test(value)){
return '用户名首尾不能出现下划线\'_\'';
}
}
});
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,198 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-fluid layui-anim layui-anim-fadein">
<div class="layui-card">
<div class="layui-card-header">
<span class="layui-breadcrumb" lay-filter="breadcrumb" style="visibility: visible;">
<a class="close" href="javascript:void(0);">上级列表</a><span lay-separator="">/</span>
<a href="javascript:void(0);"><cite>编辑内容</cite></a>
</span>
</div>
<div class="layui-card-body" style="padding: 15px;">
<form class="layui-form layui-form-pane" lay-filter="dataForm">
<div class="layui-row">
<div class="layui-form-item">
<label class="layui-form-label">用户名 *</label>
<div class="layui-input-block">
<input type="text" name="userUsername" lay-verify="userUsername" placeholder="请输入用户名" class="layui-input" readonly>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" name="userPassword" placeholder="修改密码,请输入新密码,不修改为空" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">昵称 *</label>
<div class="layui-input-block">
<input type="text" name="userName" lay-verify="required" placeholder="请输入昵称" class="layui-input">
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">类型 *</label>
<div class="layui-input-block">
<input type="radio" name="userType" value="1" title="系统用户">
<input type="radio" name="userType" value="2" title="普通用户">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">状态 *</label>
<div class="layui-input-block">
<select name="userState" lay-verify="required">
<option value="0">正常</option>
<option value="1">冻结</option>
<option value="2">锁定</option>
</select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">手机</label>
<div class="layui-input-block">
<input type="number" name="userPhone" placeholder="请输入手机" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">邮箱</label>
<div class="layui-input-block">
<input type="text" name="userEmail" placeholder="请输入邮箱" class="layui-input">
</div>
</div>
<div class="layui-form-item layui-form-text">
<label class="layui-form-label">头像</label>
<div class="layui-input-block">
<div class="layui-textarea">
<img id="avatarImage" src="assets/images/profile-photo.jpg" title="点击修改头像">
<input type="hidden" id="userAvatar" name="userAvatar">
</div>
</div>
</div>
</div>
<div class="layui-form-item layui-layout-admin">
<div class="layui-input-block">
<div class="layui-footer" style="left: 0;">
<button type="button" class="layui-btn" lay-submit lay-filter="submitForm">提交编辑</button>
<button type="button" class="layui-btn layui-btn-primary close">返回上级</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'form', 'laydate'], function(){
var $ = layui.$;
var form = layui.form;
var userId = top.restAjax.params(window.location.href).userId;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
// 初始化
function initData() {
var self = this;
var loadLayerIndex;
top.restAjax.get(top.restAjax.path('api/user/get/{userId}', [userId]), {}, null, function(code, data) {
form.val('dataForm', {
userAvatar: data.userAvatar,
userUsername: data.userUsername,
userName: data.userName,
userType: data.userType +'',
userState: data.userState +'',
userPhone: data.userPhone,
userEmail: data.userEmail.toString(),
});
form.render(null, 'dataForm');
if($('#userAvatar').val() != '') {
$('#avatarImage').attr('src', 'route/file/downloadfile/false/' + $('#userAvatar').val());
} else {
$('#userAvatar').val($('#userAvatar').val());
}
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.loading, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
}
initData();
// 提交表单
form.on('submit(submitForm)', function(formData) {
var authorizedGrantTypes = top.restAjax.checkBoxToString(formData.field, 'authorizedGrantTypes');
formData.field.authorizedGrantTypes = authorizedGrantTypes;
top.dialog.confirm(top.dataMessage.commit, function(index) {
top.dialog.close(index);
var loadLayerIndex;
top.restAjax.put(top.restAjax.path('api/user/update/{userId}', [userId]), formData.field, null, function(code, data) {
var layerIndex = top.dialog.msg(top.dataMessage.commitSuccess, {
time: 0,
btn: [top.dataMessage.button.yes, top.dataMessage.button.no],
shade: 0.3,
yes: function(index) {
top.dialog.close(index);
window.location.reload();
},
btn2: function() {
closeBox();
}
});
}, function(code, data) {
top.dialog.msg(data.msg);
}, function() {
loadLayerIndex = top.dialog.msg(top.dataMessage.committing, {icon: 16, time: 0, shade: 0.3});
}, function() {
top.dialog.close(loadLayerIndex);
});
});
return false;
});
form.verify({
userUsername: function(value, item) {
if(!new RegExp('^[a-zA-Z0-9_\\s]+$').test(value)) {
return '用户名不能有特殊字符';
}
if(/(^\_)|(\__)|(\_+$)/.test(value)){
return '用户名首尾不能出现下划线\'_\'';
}
}
});
$('#avatarImage').on('click', function() {
top.dialog.open({
url: 'route/file/uploadimage/v2?fileId='+ $('#userAvatar').val(),
title: '上传头像',
width: '800px',
height: '470px',
onClose: function() {
var uploadImage = top.dialog.dialogData.uploadImage;
if(typeof(uploadImage) != 'undefined' && null != uploadImage && '' != uploadImage) {
$('#avatarImage').attr('src', 'route/file/downloadfile/false/' + uploadImage);
$('#userAvatar').val(uploadImage);
}
}
})
});
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>

View File

@ -0,0 +1,90 @@
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<base th:href="${#request.getContextPath() + '/'}">
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="assets/fonts/font-awesome/css/font-awesome.css"/>
<link rel="stylesheet" href="assets/layuiadmin/layui/css/layui.css" media="all">
<link rel="stylesheet" href="assets/layuiadmin/style/admin.css" media="all">
</head>
<body>
<div class="layui-anim layui-anim-fadein">
<div class="layui-card" style="text-align: center;">
<div class="layui-card-body" style="padding: 15px;">
<blockquote class="layui-elem-quote">下载“下载模板”整理数据点击“导入数据”上传格式为xls或xlsx</blockquote>
<button type="button" class="layui-btn layui-btn" onclick="window.open('route/user/upload/upload-excel-template')">
<i class="fa fa-lg fa-cloud-download"></i> 下载模板
</button>
<button type="button" class="layui-btn layui-btn" id="uploadExcel">
<i class="fa fa-lg fa-cloud-upload"></i> 导入数据
</button>
</div>
</div>
</div>
<script src="assets/layuiadmin/layui/layui.js"></script>
<script>
layui.config({
base: 'assets/layuiadmin/' //静态资源所在路径
}).extend({
index: 'lib/index' //主入口模块
}).use(['index', 'upload'], function(){
var $ = layui.$;
var form = layui.form;
function closeBox() {
parent.layer.close(parent.layer.getFrameIndex(window.name));
}
// 初始化Excel上传
function initExcelUpload() {
// Excel上传
var uploadLoading;
layui.upload.render({
elem: '#uploadExcel',
url: 'api/user/importexcel',
accept: 'file',
exts: 'xls|xlsx',
field: 'excel',
before: function() {
uploadLoading = layer.msg('正在上传,请稍后...', {icon: 16, time: 0, shade: 0.3});
},
done: function(data) {
layer.close(uploadLoading);
if(data.failedCount > 0) {
layer.open({
type: 1,
title: false,
closeBtn: 0,
shadeClose: true,
skin: '',
content: '<div style="padding: 15px;">' +
'<div>失败数量:'+ data.failedCount +'</div><br/>' +
'<div><a href="javascript:void(0);" onclick="window.open(\'route/file/download/false/'+ data.errorExcel +'\');">点击下载错误信息</a></div>' +
'</div>'
});
} else {
layer.msg('导入成功', {time: 2000}, function() {
closeBox();
});
}
},
error: function(data, index){
layer.close(uploadLoading);
if(data != null) {
top.dialog.msg(data.msg);
}
},
});
}
initExcelUpload();
$('.close').on('click', function() {
closeBox();
});
});
</script>
</body>
</html>