完成管理后台用户管理及登陆
This commit is contained in:
commit
7f06178d2f
|
|
@ -0,0 +1,35 @@
|
|||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/*
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.jinrui</groupId>
|
||||
<artifactId>reference</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>admin</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.jinrui</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>${jedis.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
package com.jinrui.reference.admin;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.util.StringUtils;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.JedisPoolConfig;
|
||||
|
||||
@SpringBootApplication(scanBasePackages = {
|
||||
"com.jinrui.reference.admin",
|
||||
"com.jinrui.reference.core"
|
||||
})
|
||||
@MapperScan({
|
||||
"com.jinrui.reference.admin.mapper",
|
||||
"com.jinrui.reference.core.mapper"})
|
||||
public class AdminApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(AdminApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JedisPool jedisPool(@Value("${redis.host}") String host,
|
||||
@Value("${redis.port}") int port,
|
||||
@Value("${redis.timeout:1000}") int timeout,
|
||||
@Value("${redis.password:}") String password) {
|
||||
if (StringUtils.hasText(password)) {
|
||||
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
|
||||
return new JedisPool(jedisPoolConfig, host, port, timeout, password);
|
||||
}
|
||||
return new JedisPool(host, port);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
package com.jinrui.reference.admin.controller;
|
||||
|
||||
import com.jinrui.reference.admin.model.dto.login.AdminUserBanDTO;
|
||||
import com.jinrui.reference.admin.model.dto.login.AdminUserCreateDTO;
|
||||
import com.jinrui.reference.admin.model.dto.login.AdminUserDeleteDTO;
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import com.jinrui.reference.admin.model.vo.admin.user.AdminUserVO;
|
||||
import com.jinrui.reference.admin.service.AdminJwtService;
|
||||
import com.jinrui.reference.admin.service.AdminUserService;
|
||||
import com.jinrui.reference.core.model.vo.PageObject;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/admin/user")
|
||||
public class AdminUserController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AdminUserController.class);
|
||||
|
||||
private final AdminUserService adminUserService;
|
||||
|
||||
public AdminUserController(AdminUserService adminUserService) {
|
||||
this.adminUserService = adminUserService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理后台分页搜索接口
|
||||
*
|
||||
* @param token 登陆Token
|
||||
* @param name 用户昵称 模糊搜索
|
||||
* @param phone 用户手机号 模糊搜索
|
||||
* @param page 分页参数 当前页码 默认第一页
|
||||
* @param size 分页参数 当前页长度 默认10条
|
||||
* @return 分页搜索结果
|
||||
*/
|
||||
@GetMapping
|
||||
public PageObject<AdminUserVO> queryAdminUser(@RequestHeader("auth-token") String token,
|
||||
@RequestParam(value = "name", required = false) String name,
|
||||
@RequestParam(value = "phone", required = false) String phone,
|
||||
@RequestParam(value = "page", required = false, defaultValue = "1") int page,
|
||||
@RequestParam(value = "size", required = false, defaultValue = "10") int size) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return PageObject.failedPage("登陆Token为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return PageObject.failedPage("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUser.getId());
|
||||
return PageObject.failedPage("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
log.info("path: /admin/user, method: GET, request user id: {}, name: {}, phone: {}, page: {}, size: {}",
|
||||
adminUser.getId(), name, phone, page, size);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return PageObject.failedPage(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
return adminUserService.findAdminUser(name, phone, page, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理后台用户封禁接口
|
||||
*
|
||||
* @param token 登陆Token
|
||||
* @param adminUserBanDTO 要封禁的用户ID
|
||||
* @return 封禁结果
|
||||
*/
|
||||
@PostMapping("/ban")
|
||||
public ResultObject<Void> ban(@RequestHeader("auth-token") String token,
|
||||
@RequestBody AdminUserBanDTO adminUserBanDTO) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
Long id = adminUserBanDTO.getId();
|
||||
if (id == null) {
|
||||
log.warn("要封禁的用户ID为空!");
|
||||
return ResultObject.failed("要封禁的用户ID为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUser.getId());
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (Objects.equals(adminUserId, id)) {
|
||||
log.warn("用户(id = {})尝试自己封禁自己,已禁止该操作", id);
|
||||
return ResultObject.failed("请勿自己封禁自己!");
|
||||
}
|
||||
|
||||
log.info("path: /admin/user/ban, method: POST, request user id: {}, ban user id: {}", adminUserId, id);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
return adminUserService.ban(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理后台删除用户接口
|
||||
*
|
||||
* @param token 登陆Token
|
||||
* @param adminUserDeleteDTO 要删除的用户ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
@DeleteMapping
|
||||
public ResultObject<Void> delete(@RequestHeader("auth-token") String token,
|
||||
@RequestBody AdminUserDeleteDTO adminUserDeleteDTO) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
Long id = adminUserDeleteDTO.getId();
|
||||
if (id == null) {
|
||||
log.warn("要删除的用户ID为空!");
|
||||
return ResultObject.failed("要删除的用户ID为空!");
|
||||
}
|
||||
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUser.getId());
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
Long adminUserId = adminUser.getId();
|
||||
if (Objects.equals(adminUserId, id)) {
|
||||
log.warn("用户(id = {})尝试自己删除自己,已禁止该操作", id);
|
||||
return ResultObject.failed("请勿自己删除自己!");
|
||||
}
|
||||
|
||||
log.info("path: /admin/user, method: DELETE, request user id: {}, delete user id: {}", adminUserId, id);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
return adminUserService.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理后台创建用户接口
|
||||
*
|
||||
* @param token 登陆Token
|
||||
* @param adminUserCreateDTO 要创建的用户昵称及手机号
|
||||
* @return 创建结果
|
||||
*/
|
||||
@PostMapping("/create")
|
||||
public ResultObject<Void> createUser(@RequestHeader("auth-token") String token,
|
||||
@RequestBody AdminUserCreateDTO adminUserCreateDTO) {
|
||||
if (!StringUtils.hasText(token)) {
|
||||
return ResultObject.failed("登陆Token为空!");
|
||||
}
|
||||
|
||||
String phone = adminUserCreateDTO.getPhone();
|
||||
if (!StringUtils.hasText(phone)) {
|
||||
return ResultObject.failed("手机号不可为空!");
|
||||
}
|
||||
|
||||
String name = adminUserCreateDTO.getName();
|
||||
try {
|
||||
AdminUser adminUser = AdminJwtService.parseToken(token);
|
||||
if (adminUser == null) {
|
||||
log.warn("解析token {}拿不到AdminUser对象!", token);
|
||||
return ResultObject.failed("登陆Token有误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("当前用户已被封禁! id = {}", adminUser.getId());
|
||||
return ResultObject.failed("当前用户已被封禁!请联系系统管理员!");
|
||||
}
|
||||
|
||||
log.info("path: /admin/user/create, method: POST, request user id: {}, name: {}, phone: {}",
|
||||
adminUser.getId(), name, phone);
|
||||
} catch (Exception e) {
|
||||
log.error("解析登陆Token出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
|
||||
return adminUserService.create(name, phone);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.jinrui.reference.admin.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.admin.model.dto.login.LoginDTO;
|
||||
import com.jinrui.reference.admin.model.dto.login.SendCaptchaDTO;
|
||||
import com.jinrui.reference.admin.model.vo.login.LoginVO;
|
||||
import com.jinrui.reference.admin.service.AdminUserService;
|
||||
import com.jinrui.reference.core.controller.BaseController;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/login")
|
||||
public class LoginController extends BaseController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LoginController.class);
|
||||
|
||||
private final AdminUserService adminUserService;
|
||||
|
||||
public LoginController(ObjectMapper objectMapper,
|
||||
AdminUserService adminUserService) {
|
||||
super(objectMapper);
|
||||
this.adminUserService = adminUserService;
|
||||
}
|
||||
|
||||
@PostMapping("/captcha")
|
||||
public ResultObject<String> sendCaptcha(@RequestBody SendCaptchaDTO sendCaptchaDTO) {
|
||||
String phone = sendCaptchaDTO.getPhone();
|
||||
log.info("path: /login/captcha, phone: {}", phone);
|
||||
ResultObject<String> resultObject = adminUserService.sendCaptcha(phone);
|
||||
super.logResponse(resultObject);
|
||||
return resultObject;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResultObject<LoginVO> login(@RequestBody LoginDTO loginDTO) {
|
||||
log.info("path: /login, phone: {}, captcha: {}", loginDTO.getPhone(), loginDTO.getCaptcha());
|
||||
ResultObject<LoginVO> resultObject = adminUserService.login(loginDTO);
|
||||
super.logResponse(resultObject);
|
||||
return resultObject;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
package com.jinrui.reference.admin.mapper;
|
||||
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
import org.apache.ibatis.annotations.Insert;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Result;
|
||||
import org.apache.ibatis.annotations.Results;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.apache.ibatis.type.JdbcType;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public interface AdminUserMapper {
|
||||
|
||||
@Results({
|
||||
@Result(column = "id", property = "id", id = true),
|
||||
@Result(column = "phone", property = "phone"),
|
||||
@Result(column = "name", property = "name"),
|
||||
@Result(column = "active", property = "active"),
|
||||
@Result(column = "create_time", property = "createTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP),
|
||||
@Result(column = "update_time", property = "updateTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP)
|
||||
})
|
||||
@Select("select * from admin_user where phone = #{phone}")
|
||||
AdminUser getAdminUserByPhone(@Param("phone") String phone);
|
||||
|
||||
@Results({
|
||||
@Result(column = "id", property = "id", id = true),
|
||||
@Result(column = "phone", property = "phone"),
|
||||
@Result(column = "name", property = "name"),
|
||||
@Result(column = "active", property = "active"),
|
||||
@Result(column = "create_time", property = "createTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP),
|
||||
@Result(column = "update_time", property = "updateTime", javaType = Date.class, jdbcType = JdbcType.TIMESTAMP)
|
||||
})
|
||||
@Select("<script>" +
|
||||
"select * from admin_user " +
|
||||
"<where>" +
|
||||
"<if test=\"name != null and !name.isEmpty()\">" +
|
||||
"name like concat('%', #{name}, '%') " +
|
||||
"</if>" +
|
||||
"<if test=\"phone != null and !phone.isEmpty()\">" +
|
||||
"and phone like concat('%', #{phone}, '%') " +
|
||||
"</if>" +
|
||||
"</where>" +
|
||||
"</script>")
|
||||
List<AdminUser> queryAdminUser(@Param("name") String name, @Param("phone") String phone);
|
||||
|
||||
@Update("update admin_user set active = 0, update_time = now() where id = #{id}")
|
||||
void ban(@Param("id") long id);
|
||||
|
||||
@Delete("delete from admin_user where id = #{id}")
|
||||
void delete(@Param("id") long id);
|
||||
|
||||
@Insert("<script>" +
|
||||
"insert into admin_user(phone, create_time, update_time" +
|
||||
"<if test=\"name != null and !name.isEmpty()\">" +
|
||||
", name" +
|
||||
"</if>" +
|
||||
") values (#{phone}, now(), now()" +
|
||||
"<if test=\"name != null and !name.isEmpty()\">" +
|
||||
", #{name}" +
|
||||
"</if>" +
|
||||
")" +
|
||||
"</script>")
|
||||
void create(@Param("name") String name, @Param("phone") String phone);
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.jinrui.reference.admin.model.dto.login;
|
||||
|
||||
/**
|
||||
* 管理后台禁用用户DTO
|
||||
*/
|
||||
public class AdminUserBanDTO {
|
||||
|
||||
/**
|
||||
* 被禁用的用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.jinrui.reference.admin.model.dto.login;
|
||||
|
||||
/**
|
||||
* 管理后台创建用户DTO
|
||||
*/
|
||||
public class AdminUserCreateDTO {
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 用户手机号 不可为空
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.jinrui.reference.admin.model.dto.login;
|
||||
|
||||
/**
|
||||
* 管理后台删除用户DTO
|
||||
*/
|
||||
public class AdminUserDeleteDTO {
|
||||
|
||||
/**
|
||||
* 被删除的用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.jinrui.reference.admin.model.dto.login;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class LoginDTO {
|
||||
|
||||
private String phone;
|
||||
|
||||
private String captcha;
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getCaptcha() {
|
||||
return captcha;
|
||||
}
|
||||
|
||||
public void setCaptcha(String captcha) {
|
||||
this.captcha = captcha;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.jinrui.reference.admin.model.dto.login;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SendCaptchaDTO {
|
||||
|
||||
private String phone;
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
package com.jinrui.reference.admin.model.entity;
|
||||
|
||||
import com.auth0.jwt.interfaces.Claim;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 管理后台用户
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class AdminUser {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* <p>当前用户状态 是否启用</p>
|
||||
* true - 启动 | false - 禁用
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* 用户创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 用户修改时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
public AdminUser() {}
|
||||
|
||||
public AdminUser(DecodedJWT decodedJWT) {
|
||||
for (Map.Entry<String, Claim> entry : decodedJWT.getClaims().entrySet()) {
|
||||
String keyName = entry.getKey();
|
||||
Claim value = entry.getValue();
|
||||
switch (keyName) {
|
||||
case "id": {
|
||||
this.id = value.asLong();
|
||||
break;
|
||||
}
|
||||
case "phone": {
|
||||
this.phone = value.asString();
|
||||
break;
|
||||
}
|
||||
case "name": {
|
||||
this.name = value.asString();
|
||||
break;
|
||||
}
|
||||
case "createTime": {
|
||||
this.createTime = new Date(value.asLong());
|
||||
break;
|
||||
}
|
||||
case "updateTime": {
|
||||
this.updateTime = new Date(value.asLong());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public Date getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package com.jinrui.reference.admin.model.vo.admin.user;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 管理后台用户
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class AdminUserVO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* <p>当前用户状态 是否启用</p>
|
||||
* true - 启动 | false - 禁用
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
/**
|
||||
* 用户创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 用户修改时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
public AdminUserVO(AdminUser adminUser) {
|
||||
this.id = adminUser.getId();
|
||||
this.phone = adminUser.getPhone();
|
||||
this.name = adminUser.getName();
|
||||
this.active = adminUser.isActive();
|
||||
this.createTime = adminUser.getCreateTime();
|
||||
this.updateTime = adminUser.getUpdateTime();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public Date getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
package com.jinrui.reference.admin.model.vo.login;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import com.jinrui.reference.admin.service.AdminJwtService;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 登陆返回值
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LoginVO {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户手机号
|
||||
*/
|
||||
private String phone;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 用户登陆Token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 用户创建时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 用户修改时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
public LoginVO(AdminUser adminUser) {
|
||||
this.id = adminUser.getId();
|
||||
this.phone = adminUser.getPhone();
|
||||
this.name = adminUser.getName();
|
||||
this.token = AdminJwtService.generateToken(adminUser);
|
||||
this.createTime = adminUser.getCreateTime();
|
||||
this.updateTime = adminUser.getUpdateTime();
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public Date getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public void setUpdateTime(Date updateTime) {
|
||||
this.updateTime = updateTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package com.jinrui.reference.admin.service;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTCreator;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public final class AdminJwtService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AdminJwtService.class);
|
||||
private static final String SECRET = "R!E@F#E$R%E^N&C*E";
|
||||
|
||||
private AdminJwtService() {}
|
||||
|
||||
/**
|
||||
* 管理后台根据用户对象生成JWT TOKEN
|
||||
*
|
||||
* @param adminUser 管理后台用户对象
|
||||
* @return JWT TOKEN
|
||||
*/
|
||||
public static String generateToken(AdminUser adminUser) {
|
||||
Long id = adminUser.getId();
|
||||
String phone = adminUser.getPhone();
|
||||
String name = adminUser.getName();
|
||||
long createTime = adminUser.getCreateTime().getTime();
|
||||
long updateTime = adminUser.getUpdateTime().getTime();
|
||||
JWTCreator.Builder jwtBuilder = JWT.create();
|
||||
jwtBuilder.withClaim("id", id);
|
||||
jwtBuilder.withClaim("phone", phone);
|
||||
jwtBuilder.withClaim("name", name);
|
||||
jwtBuilder.withClaim("createTime", createTime);
|
||||
jwtBuilder.withClaim("updateTime", updateTime);
|
||||
jwtBuilder.withClaim("timestamp", System.currentTimeMillis());
|
||||
return jwtBuilder.sign(Algorithm.HMAC256(SECRET));
|
||||
}
|
||||
|
||||
public static AdminUser parseToken(String token) {
|
||||
if (token == null) {
|
||||
throw new NullPointerException("token is null!");
|
||||
}
|
||||
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET))
|
||||
.withClaimPresence("id")
|
||||
.withClaimPresence("phone")
|
||||
.withClaimPresence("name")
|
||||
.withClaimPresence("createTime")
|
||||
.withClaimPresence("updateTime")
|
||||
.withClaimPresence("timestamp")
|
||||
.build();
|
||||
try {
|
||||
DecodedJWT decodedJWT = jwtVerifier.verify(token);
|
||||
return new AdminUser(decodedJWT);
|
||||
} catch (JWTVerificationException e) {
|
||||
log.error("error in verifying token!", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
package com.jinrui.reference.admin.service;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.admin.mapper.AdminUserMapper;
|
||||
import com.jinrui.reference.admin.model.dto.login.LoginDTO;
|
||||
import com.jinrui.reference.admin.model.entity.AdminUser;
|
||||
import com.jinrui.reference.admin.model.vo.admin.user.AdminUserVO;
|
||||
import com.jinrui.reference.admin.model.vo.login.LoginVO;
|
||||
import com.jinrui.reference.core.model.vo.PageObject;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class AdminUserService {
|
||||
|
||||
private static final String REDIS_LOGIN_LOCK_KEY = "login-lock-";
|
||||
private static final String REDIS_KEY_SEND_CAPTCHA_TO_PREFIX = "send-captcha-to-";
|
||||
private static final String REDIS_KEY_CAPTCHA = "login-captcha-";
|
||||
private static final Logger log = LoggerFactory.getLogger(AdminUserService.class);
|
||||
|
||||
private final JedisPool jedisPool;
|
||||
private final AdminUserMapper adminUserMapper;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public AdminUserService(JedisPool jedisPool,
|
||||
AdminUserMapper adminUserMapper,
|
||||
ObjectMapper objectMapper) {
|
||||
this.jedisPool = jedisPool;
|
||||
this.adminUserMapper = adminUserMapper;
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>给指定手机号发送验证码,如果不是系统中已有的手机号则不发送,被禁用的账号不发送</p>
|
||||
* <p>同一个手机号60秒之内只能发送一封验证码短信,验证码有效期10分钟</p>
|
||||
*
|
||||
* @param phone 要发送验证码的手机号
|
||||
*/
|
||||
public ResultObject<String> sendCaptcha(String phone) {
|
||||
if (!StringUtils.hasText(phone)) {
|
||||
return ResultObject.failed("手机号为空!");
|
||||
}
|
||||
|
||||
String redisLockKey = getLoginLockKey(phone);
|
||||
try (Jedis jedis = jedisPool.getResource()) {
|
||||
long incrResult = jedis.incr(redisLockKey);
|
||||
if (incrResult > 1) {
|
||||
jedis.decr(redisLockKey);
|
||||
return ResultObject.failed("系统繁忙,请稍后再试!");
|
||||
}
|
||||
jedis.expire(redisLockKey, 3L);
|
||||
|
||||
String redisCaptchaKey = getRedisCaptchaKey(phone);
|
||||
incrResult = jedis.incr(redisCaptchaKey);
|
||||
if (incrResult > 1) {
|
||||
log.warn("手机号{}在一分钟内已发送过短信,请勿重复发送!", phone);
|
||||
jedis.decr(redisLockKey);
|
||||
jedis.decr(redisCaptchaKey);
|
||||
return ResultObject.failed("该手机号一分钟内已发送过短信,请勿重复发送!");
|
||||
}
|
||||
jedis.expire(redisCaptchaKey, 60L);
|
||||
|
||||
AdminUser adminUser = adminUserMapper.getAdminUserByPhone(phone);
|
||||
if (adminUser == null) {
|
||||
String errorMessage = String.format("找不到手机号为%s的用户!", phone);
|
||||
log.warn(errorMessage);
|
||||
jedis.decr(redisLockKey);
|
||||
return ResultObject.failed(errorMessage);
|
||||
}
|
||||
if (!adminUser.isActive()) {
|
||||
log.warn("被禁用的用户(phone = {})尝试登陆!", phone);
|
||||
jedis.decr(redisLockKey);
|
||||
return ResultObject.failed("当前用户已被禁用,请联系系统管理员!");
|
||||
}
|
||||
|
||||
String randomCaptcha = randomCaptcha();
|
||||
log.info("记录手机号{}的登陆验证码: {}", phone, randomCaptcha);
|
||||
String redisCaptchaListKey = getRedisCaptchaListKey(phone);
|
||||
String captchaList = jedis.get(redisCaptchaListKey);
|
||||
if (!StringUtils.hasText(captchaList) || "nil".equals(captchaList)) {
|
||||
captchaList = randomCaptcha;
|
||||
} else {
|
||||
captchaList += ("," + randomCaptcha);
|
||||
}
|
||||
log.info("手机号{}当前的验证码列表: {}", phone, captchaList);
|
||||
jedis.set(redisCaptchaListKey, captchaList);
|
||||
jedis.expire(redisCaptchaListKey, 600L);
|
||||
jedis.decr(redisLockKey);
|
||||
return ResultObject.success(randomCaptcha);
|
||||
} catch (Exception e) {
|
||||
log.error("sendCaptcha异常!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据验证码进行登陆,登陆后给当前手机发送的所有验证码无效
|
||||
*
|
||||
* @param loginDTO 登陆参数
|
||||
* @return 登陆结果
|
||||
*/
|
||||
public ResultObject<LoginVO> login(LoginDTO loginDTO) {
|
||||
String phone = loginDTO.getPhone();
|
||||
if (!StringUtils.hasText(phone)) {
|
||||
return ResultObject.failed("手机号为空!");
|
||||
}
|
||||
String captcha = loginDTO.getCaptcha();
|
||||
if (!StringUtils.hasText(captcha)) {
|
||||
return ResultObject.failed("验证码为空!");
|
||||
}
|
||||
int captchaLength = captcha.length();
|
||||
if (captchaLength != 6) {
|
||||
log.warn("手机号{}登陆时试图使用错误的验证码{}", phone, captcha);
|
||||
return ResultObject.failed("验证码错误,请重新输入!");
|
||||
}
|
||||
|
||||
String redisLockKey = getLoginLockKey(phone);
|
||||
try (Jedis jedis = jedisPool.getResource()) {
|
||||
long incrResult = jedis.incr(redisLockKey);
|
||||
if (incrResult > 1) {
|
||||
jedis.decr(redisLockKey);
|
||||
return ResultObject.failed("系统繁忙,请稍后再试!");
|
||||
}
|
||||
jedis.expire(redisLockKey, 3L);
|
||||
|
||||
String redisCaptchaListKey = getRedisCaptchaListKey(phone);
|
||||
String captchaList = jedis.get(redisCaptchaListKey);
|
||||
if (!StringUtils.hasText(captchaList)) {
|
||||
log.warn("没有找到给手机号{}发送的验证码!", phone);
|
||||
jedis.decr(redisLockKey);
|
||||
return ResultObject.failed("验证码错误,请重新输入!");
|
||||
}
|
||||
|
||||
String[] split = captchaList.split(",");
|
||||
for (String available : split) {
|
||||
if (Objects.equals(captcha, available)) {
|
||||
log.info("手机号{}验证码校验成功!", phone);
|
||||
AdminUser adminUser = adminUserMapper.getAdminUserByPhone(phone);
|
||||
if (adminUser == null) {
|
||||
return ResultObject.failed("用户不存在,请联系系统管理员!");
|
||||
}
|
||||
if (!adminUser.isActive()) {
|
||||
return ResultObject.failed("用户已被禁用,请联系系统管理员!");
|
||||
}
|
||||
LoginVO loginVO = new LoginVO(adminUser);
|
||||
jedis.del(redisLockKey, redisCaptchaListKey);
|
||||
return ResultObject.success(loginVO);
|
||||
}
|
||||
}
|
||||
log.info("没有给手机{}发送过验证码{}, 已发送过的验证码是[{}]", phone, captcha, captchaList);
|
||||
jedis.decr(redisLockKey);
|
||||
return ResultObject.failed("验证码错误,请重新输入!");
|
||||
} catch (Exception e) {
|
||||
log.error("login错误!", e);
|
||||
return ResultObject.failed(500, "服务端错误,请联系系统管理员!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询管理后台用户
|
||||
*
|
||||
* @param name 用户名 模糊匹配
|
||||
* @param phone 手机号 模糊匹配
|
||||
* @param page 当前页码 默认第一页
|
||||
* @param size 每页长度 默认10条
|
||||
* @return 查询结果
|
||||
*/
|
||||
public PageObject<AdminUserVO> findAdminUser(String name, String phone, int page, int size) {
|
||||
List<AdminUser> resultList = adminUserMapper.queryAdminUser(name, phone);
|
||||
if (CollectionUtils.isEmpty(resultList)) {
|
||||
return PageObject.empty(page);
|
||||
}
|
||||
|
||||
PageObject<AdminUserVO> pageObject = new PageObject<>();
|
||||
pageObject.setTotal(resultList.size());
|
||||
List<AdminUserVO> responseList = resultList.stream()
|
||||
.skip((long) (page - 1) * size)
|
||||
.limit(size)
|
||||
.map(AdminUserVO::new)
|
||||
.collect(Collectors.toList());
|
||||
pageObject.setCurrent(page);
|
||||
pageObject.setSize(Math.min(size, resultList.size()));
|
||||
pageObject.setCode(200);
|
||||
pageObject.setData(responseList);
|
||||
|
||||
try {
|
||||
String pageString = objectMapper.writeValueAsString(pageObject);
|
||||
log.info("查询管理后台结果: {}", pageString);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("查询用户返回分页对象json映射报错!", e);
|
||||
}
|
||||
return pageObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理后台封禁用户接口
|
||||
*
|
||||
* @param id 要封禁的用户ID
|
||||
* @return 封禁结果
|
||||
*/
|
||||
public ResultObject<Void> ban(Long id) {
|
||||
try {
|
||||
adminUserMapper.ban(id);
|
||||
} catch (Exception e) {
|
||||
log.error("ban错误!", e);
|
||||
return ResultObject.failed(500, "服务端错误!请联系系统管理员!");
|
||||
}
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理后台删除用户接口
|
||||
*
|
||||
* @param id 要删除的用户ID
|
||||
* @return 删除结果
|
||||
*/
|
||||
public ResultObject<Void> delete(Long id) {
|
||||
try {
|
||||
adminUserMapper.delete(id);
|
||||
} catch (Exception e) {
|
||||
log.error("delete错误!", e);
|
||||
return ResultObject.failed(500, "服务端错误!请联系系统管理员!");
|
||||
}
|
||||
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
public ResultObject<Void> create(String name, String phone) {
|
||||
try {
|
||||
AdminUser adminUser = adminUserMapper.getAdminUserByPhone(phone);
|
||||
if (adminUser != null) {
|
||||
log.warn("手机号{}已被注册!", phone);
|
||||
return ResultObject.failed("手机号已存在,请更换");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("根据手机号查询用户出错!", e);
|
||||
return ResultObject.failed(500, "服务端错误!请联系系统管理员!");
|
||||
}
|
||||
|
||||
try {
|
||||
adminUserMapper.create(name, phone);
|
||||
} catch (Exception e) {
|
||||
log.error("注册用户报错!", e);
|
||||
return ResultObject.failed(500, "服务端错误!请联系系统管理员!");
|
||||
}
|
||||
|
||||
return ResultObject.success();
|
||||
}
|
||||
|
||||
private static String getRedisCaptchaKey(String phone) {
|
||||
return REDIS_KEY_SEND_CAPTCHA_TO_PREFIX + phone;
|
||||
}
|
||||
|
||||
private static String getRedisCaptchaListKey(String phone) {
|
||||
return REDIS_KEY_CAPTCHA + phone;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机六位数字验证码
|
||||
*
|
||||
* @return 数字验证码
|
||||
*/
|
||||
private static String randomCaptcha() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int nextInt = random.nextInt(10);
|
||||
stringBuilder.append(nextInt);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
private static String getLoginLockKey(String phone) {
|
||||
return REDIS_LOGIN_LOCK_KEY + phone;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
server:
|
||||
port: 13579
|
||||
oss:
|
||||
ak: LTAI5t8z9QNdCG6b54mDgx8p
|
||||
sk: F3M41hTgH8g99ZgVWyelj42825YbZM
|
||||
roleArn: acs:ram::1647420045565932:role/ramoss
|
||||
endPoint: oss-cn-hangzhou.aliyuncs.com
|
||||
region: oss-cn-hangzhou
|
||||
bucketName: lengfeng-test
|
||||
baseUrl: https://lengfeng-test.oss-cn-hangzhou.aliyuncs.com
|
||||
sts:
|
||||
endPoint: sts.cn-hangzhou.aliyuncs.com
|
||||
spring:
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/reference?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8&allowMultiQueries=true
|
||||
username: root
|
||||
password: Aa123456@
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
port: 6379
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.jinrui</groupId>
|
||||
<artifactId>reference</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>core</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<bouncycastle.version>1.70</bouncycastle.version>
|
||||
<jwt.version>4.4.0</jwt.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
<artifactId>aliyun-sdk-oss</artifactId>
|
||||
<version>3.17.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.auth0</groupId>
|
||||
<artifactId>java-jwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcutil-jdk15on</artifactId>
|
||||
<version>${bouncycastle.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.jinrui.reference.core;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebConfig implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 跨域访问支持
|
||||
*/
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOriginPatterns("*")
|
||||
.allowCredentials(true)
|
||||
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH")
|
||||
.maxAge(3600);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.jinrui.reference.core.controller;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.jinrui.reference.core.model.vo.ResultObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class BaseController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseController.class);
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
protected BaseController(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
protected void logResponse(ResultObject<?> resultObject) {
|
||||
try {
|
||||
String resultString = objectMapper.writeValueAsString(resultObject);
|
||||
log.info("result: {}", resultString);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("error in parsing result object into string!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.jinrui.reference.core.model.vo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页对象
|
||||
*
|
||||
* @param <T> 返回值类型
|
||||
*/
|
||||
public class PageObject<T> extends ResultObject<List<T>> {
|
||||
|
||||
/**
|
||||
* 分页页码 默认从1开始
|
||||
*/
|
||||
private int current;
|
||||
|
||||
/**
|
||||
* 分页长度 默认为10
|
||||
*/
|
||||
private int size;
|
||||
|
||||
/**
|
||||
* 数据总数
|
||||
*/
|
||||
private int total;
|
||||
|
||||
public static <T> PageObject<T> empty(int page) {
|
||||
PageObject<T> pageObject = new PageObject<>();
|
||||
pageObject.setCode(200);
|
||||
pageObject.setCurrent(page);
|
||||
pageObject.setSize(0);
|
||||
pageObject.setTotal(0);
|
||||
pageObject.setData(new ArrayList<>());
|
||||
return pageObject;
|
||||
}
|
||||
|
||||
public static <T> PageObject<T> failedPage(int code, String message) {
|
||||
PageObject<T> pageObject = new PageObject<>();
|
||||
pageObject.setCode(code);
|
||||
pageObject.setMsg(message);
|
||||
return pageObject;
|
||||
}
|
||||
|
||||
public static <T> PageObject<T> failedPage(String message) {
|
||||
return failedPage(400, message);
|
||||
}
|
||||
|
||||
public int getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void setCurrent(int current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getTotal() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public void setTotal(int total) {
|
||||
this.total = total;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.jinrui.reference.core.model.vo;
|
||||
|
||||
/**
|
||||
* 通用返回结构
|
||||
*
|
||||
* @param <T> 返回对象类型
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ResultObject<T> {
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private int code;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String msg;
|
||||
|
||||
/**
|
||||
* 返回对象
|
||||
*/
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 查询请求成功返回
|
||||
* @param data 请求返回值
|
||||
* @return 返回结构体
|
||||
* @param <T> 返回值类型
|
||||
*/
|
||||
public static <T> ResultObject<T> success(T data) {
|
||||
ResultObject<T> resultObject = new ResultObject<>();
|
||||
resultObject.code = 200;
|
||||
resultObject.data = data;
|
||||
return resultObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改请求成功返回
|
||||
* @return 返回结构体
|
||||
* @param <T> 返回值类型
|
||||
*/
|
||||
public static <T> ResultObject<T> success() {
|
||||
return success(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端参数错误返回
|
||||
* @param msg 错误信息
|
||||
* @return 返回结构体
|
||||
* @param <T> 返回值类型
|
||||
*/
|
||||
public static <T> ResultObject<T> failed(String msg) {
|
||||
return failed(400, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义状态码错误返回
|
||||
* @param msg 错误信息
|
||||
* @return 返回结构体
|
||||
* @param <T> 返回值类型
|
||||
*/
|
||||
public static <T> ResultObject<T> failed(int code, String msg) {
|
||||
ResultObject<T> resultObject = new ResultObject<>();
|
||||
resultObject.code = code;
|
||||
resultObject.msg = msg;
|
||||
return resultObject;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
//package com.jinrui.reference.core.service;
|
||||
//
|
||||
//import com.auth0.jwt.JWT;
|
||||
//import com.auth0.jwt.JWTCreator;
|
||||
//import com.auth0.jwt.JWTVerifier;
|
||||
//import com.auth0.jwt.algorithms.Algorithm;
|
||||
//import com.auth0.jwt.exceptions.JWTVerificationException;
|
||||
//import com.auth0.jwt.interfaces.Claim;
|
||||
//import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
//
|
||||
//import org.slf4j.Logger;
|
||||
//import org.slf4j.LoggerFactory;
|
||||
//import org.springframework.stereotype.Service;
|
||||
//import org.springframework.util.StringUtils;
|
||||
//
|
||||
//@Service
|
||||
//public class JwtService {
|
||||
//
|
||||
// private static final Logger log = LoggerFactory.getLogger(JwtService.class);
|
||||
// private static final String SECRET = "R!E@F#E$R%E^N&C*E";
|
||||
//
|
||||
// /**
|
||||
// * 管理后台根据用户对象生成JWT TOKEN
|
||||
// * @param adminUser 管理后台用户对象
|
||||
// * @return JWT TOKEN
|
||||
// */
|
||||
// public String generateToken(AdminUser adminUser) {
|
||||
// Long id = adminUser.getId();
|
||||
// String username = adminUser.getUsername();
|
||||
// JWTCreator.Builder jwtBuilder = JWT.create();
|
||||
// jwtBuilder.withClaim("username", username);
|
||||
// jwtBuilder.withClaim("id", id);
|
||||
// jwtBuilder.withClaim("timestamp", System.currentTimeMillis());
|
||||
// return jwtBuilder.sign(Algorithm.HMAC256(SECRET));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 微信小程序根据用户对象生成JWT TOKEN
|
||||
// * @param miniUser 小程序用户对象
|
||||
// * @return JWT TOKEN
|
||||
// */
|
||||
// public String generateToken(MiniUser miniUser) {
|
||||
// Long id = miniUser.getId();
|
||||
// String phone = miniUser.getPhone();
|
||||
// JWTCreator.Builder jwtBuilder = JWT.create();
|
||||
// jwtBuilder.withClaim("phone", phone);
|
||||
// jwtBuilder.withClaim("id", id);
|
||||
// jwtBuilder.withClaim("timestamp", System.currentTimeMillis());
|
||||
// return jwtBuilder.sign(Algorithm.HMAC256(SECRET));
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 管理后台校验JWT TOKEN
|
||||
// * @param token token
|
||||
// * @return 校验结果
|
||||
// */
|
||||
// public AdminUser verify(String token) {
|
||||
// if (!StringUtils.hasText(token)) {
|
||||
// log.warn("管理后台token为空!");
|
||||
// return null;
|
||||
// }
|
||||
// JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET))
|
||||
// .withClaimPresence("username")
|
||||
// .withClaimPresence("id")
|
||||
// .withClaimPresence("timestamp")
|
||||
// .build();
|
||||
// try {
|
||||
// DecodedJWT decodedJWT = jwtVerifier.verify(token);
|
||||
// Claim claim = decodedJWT.getClaim("id");
|
||||
// Long adminUserId = claim.asLong();
|
||||
// log.info("JWT解析成功,管理后台用户ID: {}", adminUserId);
|
||||
// return adminUserMapper.getById(adminUserId);
|
||||
// } catch (JWTVerificationException e) {
|
||||
// log.error("JWT解析异常!token: {}", token, e);
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * 小程序校验JWT TOKEN
|
||||
// * @param token token
|
||||
// * @return 校验结果
|
||||
// */
|
||||
// public MiniUser verifyMini(String token) {
|
||||
// if (!StringUtils.hasText(token)) {
|
||||
// log.warn("小程序token为空!");
|
||||
// return null;
|
||||
// }
|
||||
// JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET))
|
||||
// .withClaimPresence("phone")
|
||||
// .withClaimPresence("id")
|
||||
// .withClaimPresence("timestamp")
|
||||
// .build();
|
||||
// try {
|
||||
// DecodedJWT decodedJWT = jwtVerifier.verify(token);
|
||||
// Claim claim = decodedJWT.getClaim("id");
|
||||
// Long miniUserId = claim.asLong();
|
||||
// log.info("JWT解析成功,小程序用户ID: {}", miniUserId);
|
||||
// return miniUserMapper.getById(miniUserId);
|
||||
// } catch (JWTVerificationException e) {
|
||||
// log.error("JWT解析异常!token: {}", token, e);
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.jinrui</groupId>
|
||||
<artifactId>reference</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>mini</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>admin</module>
|
||||
<module>mini</module>
|
||||
<module>core</module>
|
||||
</modules>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.7.18</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<mybatis-version>2.3.2</mybatis-version>
|
||||
</properties>
|
||||
|
||||
<groupId>com.jinrui</groupId>
|
||||
<artifactId>reference</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>reference</name>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>hejiuxiaofendui-flexible-wesley</id>
|
||||
<name>wesley</name>
|
||||
<url>https://hejiuxiaofendui-maven.pkg.coding.net/repository/flexible/wesley/</url>
|
||||
<releases>
|
||||
<enabled>true</enabled>
|
||||
</releases>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>${mybatis-version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.1</version>
|
||||
<configuration>
|
||||
<testFailureIgnore>true</testFailureIgnore>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
Loading…
Reference in New Issue