Feat: add login interface

This commit is contained in:
xinsin 2023-04-19 23:21:10 +08:00
parent 89ff44cfcf
commit a429feb9a8
31 changed files with 1103 additions and 109 deletions

13
pom.xml
View File

@ -87,6 +87,7 @@
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
@ -106,5 +107,17 @@
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,23 +0,0 @@
package top.xinsin.config;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author xinsin
* Created On 2023/4/3 15:55
* @version 1.0
*/
@SpringBootConfiguration
public class GlobalWebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOriginPatterns("*")
.allowedMethods("GET", "POST", "DELETE", "PUT", "HEAD")
.allowedHeaders("*")
.exposedHeaders("*");
}
}

View File

@ -0,0 +1,38 @@
package top.xinsin.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.xinsin.interceptor.AuthorizeInterceptor;
import top.xinsin.interceptor.GlobalWebInterceptor;
/**
* @author xinsin
* Created On 2023/4/3 15:55
* @version 1.0
*/
@Configuration
public class GlobalWebMvcConfiguration implements WebMvcConfigurer {
@Autowired
private AuthorizeInterceptor interceptor;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.exposedHeaders("*");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor)
.addPathPatterns("/**")
.excludePathPatterns("/api/auth/**");
}
}

View File

@ -0,0 +1,45 @@
package top.xinsin.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import top.xinsin.util.R;
@Slf4j
@ControllerAdvice
public class InterceptResponseConfiguration implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 只有返回数据为自定义返回格式,才对数据进行处理
if (body instanceof R<?> r){
String controllerMethodName = returnType.getMethod().getName();
String controllerClassName = returnType.getDeclaringClass().getSimpleName();
String controllerClassURlPath = returnType.getDeclaringClass().getAnnotation(RequestMapping.class).value()[0];
RequestMapping annotation = returnType.getMethod().getAnnotation(RequestMapping.class);
String controllerUrlPath = annotation.path()[0];
String controllerUrlMethod = annotation.method()[0].name();
log.info("[全局响应体后处理器]-请求类:{}-请求方法:{}-请求地址:{}{}-请求方法:{}-响应状态码:{}-响应数据:{}",
controllerClassName,
controllerMethodName,
controllerClassURlPath,
controllerUrlPath,
controllerUrlMethod,
r.getStatus(),
r.getData());
response.setStatusCode(HttpStatusCode.valueOf(r.getStatus()));
}
return body;
}
}

View File

@ -1,24 +0,0 @@
package top.xinsin.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import top.xinsin.interceptor.AuthenticationInterceptor;
/**
* @author xinsin
* Created On 2023/4/3 15:54
* @version 1.0
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor()).
//拦截
addPathPatterns("/**").
//放行登录接口
excludePathPatterns("/user/login").
excludePathPatterns("/user/register");
}
}

View File

@ -8,8 +8,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig{
public class MybatisPlusConfiguration {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

View File

@ -0,0 +1,112 @@
package top.xinsin.config;
import com.alibaba.fastjson2.JSONObject;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import top.xinsin.service.AccountService;
import top.xinsin.util.HttpCodes;
import top.xinsin.util.R;
import javax.sql.DataSource;
import java.io.IOException;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration {
@Resource
AccountService authorizeService;
@Autowired
DataSource dataSource;
@Bean
public SecurityFilterChain filterChain(HttpSecurity httpSecurity, PersistentTokenRepository persistentTokenRepository) throws Exception {
return httpSecurity
.authorizeHttpRequests()
.requestMatchers("/api/auth/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginProcessingUrl("/api/auth/login")
.successHandler(this::onsuccessLoginHandler)
.failureHandler(this::onFailureLoginHandler)
.and()
.logout()
.logoutUrl("/api/auth/logout")
.logoutSuccessHandler(this::onsuccessLoginHandler)
.and()
.rememberMe()
.rememberMeParameter("remember")
.tokenRepository(persistentTokenRepository)
.tokenValiditySeconds(60 * 60 * 12)
.and()
.csrf()
.disable()
.cors()
.configurationSource(this.corsConfigurationSource())
.and()
.exceptionHandling()
.authenticationEntryPoint(this::onFailureLoginHandler)
.and()
.build();
}
@Bean
public PersistentTokenRepository tokenRepository(){
JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
jdbcTokenRepository.setDataSource(dataSource);
jdbcTokenRepository.setCreateTableOnStartup(false);
return jdbcTokenRepository;
}
@Bean
public AuthenticationManager authenticationManager(HttpSecurity security) throws Exception {
return security
.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(authorizeService)
.and()
.build();
}
@Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
private CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration cors = new CorsConfiguration();
cors.addAllowedOriginPattern("*");
cors.setAllowCredentials(true);
cors.addAllowedHeader("*");
cors.addAllowedMethod("*");
cors.addExposedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", cors);
return source;
}
private void onsuccessLoginHandler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException {
httpServletResponse.setCharacterEncoding("utf-8");
if(httpServletRequest.getRequestURI().endsWith("/login"))
httpServletResponse.getWriter().write(JSONObject.toJSONString(R.success("登陆成功")));
else if(httpServletRequest.getRequestURI().endsWith("/logout"))
httpServletResponse.getWriter().write(JSONObject.toJSONString(R.success("退出登录成功")));
}
private void onFailureLoginHandler(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,AuthenticationException authentication) throws IOException {
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.getWriter().write(JSONObject.toJSONString(R.failed(HttpCodes.ACCESS_DENIED,"登录时出现了错误")));
}
}

View File

@ -0,0 +1,29 @@
package top.xinsin.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import top.xinsin.util.HttpCodes;
import top.xinsin.util.R;
/**
* <p>
* 前端控制器
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@RestController
@RequestMapping("/account")
public class AccountController {
@RequestMapping(path = "/get",method = RequestMethod.GET)
public R<String> get(){
return R.failed(HttpCodes.HTTP_CODES500,"234567890");
}
}

View File

@ -0,0 +1,20 @@
package top.xinsin.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@RestController
@RequestMapping("/permissions")
public class PermissionsController {
}

View File

@ -0,0 +1,20 @@
package top.xinsin.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 前端控制器
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@RestController
@RequestMapping("/roles")
public class RolesController {
}

View File

@ -1,56 +0,0 @@
package top.xinsin.interceptor;
import com.alibaba.fastjson2.JSONObject;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import top.xinsin.util.HttpCodes;
import top.xinsin.util.JWTUtils;
import top.xinsin.util.R;
/**
* @author xinsin
* Created On 2023/4/3 15:49
* @version 1.0
*/
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
public static final String OPTIONS = "OPTIONS";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (OPTIONS.equals(request.getMethod())) {
return true;
}
// 从http请求头中取出token
final String token = request.getHeader("Access-Token");
//解决跨域问题
response.setHeader("Access-Control-Allow-Origin","*");
//解决跨域问题
response.setHeader("Access-Control-Allow-Headers","*");
R responseData;
try {
JWTUtils.verify(token);
return true;
} catch (SignatureVerificationException e) {
log.info("用户验证了无效签名");
responseData = R.failed(HttpCodes.ACCESS_DENIED,"无效签名");
}catch (TokenExpiredException e){
log.info("用户验证的签名已过期");
responseData = R.failed(HttpCodes.INVALID_TOKEN,"签名已过期");
}catch (AlgorithmMismatchException e){
log.info("用户验证的token算法不一致");
responseData = R.failed(HttpCodes.INVALID_TOKEN,"token算法不一致");
}catch (Exception e){
log.info("token无效或者是空的");
responseData = R.failed(HttpCodes.INVALID_TOKEN,"token无效");
}
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(JSONObject.toJSONString(responseData));
return false;
}
}

View File

@ -0,0 +1,34 @@
package top.xinsin.interceptor;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import top.xinsin.mapper.AccountMapper;
import top.xinsin.pojo.Account;
@Component
public class AuthorizeInterceptor implements HandlerInterceptor {
@Autowired
private AccountMapper accountMapper;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
User user = (User)authentication.getPrincipal();
String username = user.getUsername();
Account account = accountMapper.selectOne(new LambdaQueryWrapper<Account>()
.eq(Account::getUsername,username)
.or()
.eq(Account::getEmail,username));
request.getSession().setAttribute("account", account);
return true;
}
}

View File

@ -0,0 +1,15 @@
package top.xinsin.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
@Slf4j
public class GlobalWebInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerMethod handler1 = (HandlerMethod) handler;
}
}

View File

@ -0,0 +1,18 @@
package top.xinsin.mapper;
import top.xinsin.pojo.Account;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Mapper
public interface AccountMapper extends BaseMapper<Account> {
}

View File

@ -0,0 +1,18 @@
package top.xinsin.mapper;
import top.xinsin.pojo.Permissions;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Mapper
public interface PermissionsMapper extends BaseMapper<Permissions> {
}

View File

@ -0,0 +1,18 @@
package top.xinsin.mapper;
import top.xinsin.pojo.Roles;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* Mapper 接口
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Mapper
public interface RolesMapper extends BaseMapper<Roles> {
}

View File

@ -0,0 +1,50 @@
package top.xinsin.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
/**
* <p>
*
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Data
@TableName("account")
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
@TableId("id")
private Integer id;
@TableField("username")
private String username;
@TableField("email")
private String email;
@TableField("rel_name")
private String relName;
@TableField("password")
private String password;
@TableField("status")
private Boolean status;
@TableField("role_id")
private Integer roleId;
@TableField("create_time")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("update_time")
private LocalDateTime updateTime;
@TableField("del")
private Boolean del;
}

View File

@ -0,0 +1,50 @@
package top.xinsin.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
/**
* <p>
*
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Data
@TableName("permissions")
public class Permissions implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField("permission_name")
private String permissionName;
@TableField("permission_code")
private String permissionCode;
@TableField("description")
private String description;
@TableField("account_id")
private Integer accountId;
@TableField("create_time")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
@TableField("update_time")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime updateTime;
@TableField("status")
private Boolean status;
@TableField("del")
private Boolean del;
}

View File

@ -0,0 +1,50 @@
package top.xinsin.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
/**
* <p>
*
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Data
@TableName("roles")
public class Roles implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@TableField("role_name")
private String roleName;
@TableField("description")
private String description;
@TableField("account_id")
private Integer accountId;
@TableField("create_time")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime createTime;
@TableField("update_time")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime updateTime;
@TableField("status")
private Boolean status;
@TableField("del")
private Boolean del;
}

View File

@ -0,0 +1,46 @@
package top.xinsin.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import top.xinsin.mapper.AccountMapper;
import top.xinsin.pojo.Account;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Service
public class AccountService implements UserDetailsService {
@Autowired
private AccountMapper accountMapper;
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println(username);
if(username == null) throw new UsernameNotFoundException("用户名不能为空");
Account account = accountMapper.selectOne(new LambdaQueryWrapper<Account>()
.eq(Account::getUsername,username)
.or()
.eq(Account::getEmail,username));
if(account == null) throw new UsernameNotFoundException("用户名或密码错误");
return User
.withUsername(account.getUsername())
.password(account.getPassword())
.roles(String.valueOf(account.getRoleId()))
.build();
}
}

View File

@ -0,0 +1,18 @@
package top.xinsin.service;
import org.springframework.stereotype.Service;
import top.xinsin.pojo.Permissions;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Service
public class PermissionsService {
}

View File

@ -0,0 +1,18 @@
package top.xinsin.service;
import org.springframework.stereotype.Service;
import top.xinsin.pojo.Roles;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 服务类
* </p>
*
* @author xinsin
* @since 2023-04-12
*/
@Service
public class RolesService {
}

View File

@ -10,18 +10,18 @@ public enum HttpCodes {
* 200
* 成功执行
*/
HTTP_CODES200(200,"接口一不小心执行成功啦!"),
HTTP_CODES200(202,"接口执行成功"),
/**
* 500
* 服务器错误
*/
HTTP_CODES500(500,"哎呀,错误了请节哀!"),
HTTP_CODES500(500,"服务器出现错误,请联系服务器管理员"),
/**
* 401
* 数据错误
*/
HTTP_CODES401(401,"你这请求是坏的,你不会写吗?"),
HTTP_CODES401(401,"这是一个坏的请求,请重新写入参数"),
/**
* 501
* 账号密码错误
@ -36,7 +36,7 @@ public enum HttpCodes {
* 251
* 无权限访问
*/
ACCESS_DENIED( 251,"你没有权限访问");
ACCESS_DENIED( 251,"无权访问");
private final int code;
private final String message;

View File

@ -0,0 +1,20 @@
package top.xinsin.util;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.SneakyThrows;
/**
* 将数据渲染到前端
*/
public class ServletUtils {
@SneakyThrows
public static void render(HttpServletRequest request, HttpServletResponse response,R<?> o){
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
response.setHeader("Content-type", "application/json;charset=UTF-8");
response.getWriter().print(JSON.toJSONString(o));
}
}

View File

@ -26,6 +26,9 @@ spring:
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mvc:
static-path-pattern: /static/**
security:
user:
password: 123456
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

View File

@ -0,0 +1,19 @@
<?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="top.xinsin.mapper.AccountMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="top.xinsin.pojo.Account">
<id column="id" property="id" />
<result column="username" property="username" />
<result column="email" property="email" />
<result column="rel_name" property="relName" />
<result column="password" property="password" />
<result column="status" property="status" />
<result column="role_id" property="roleId" />
<result column="createTime" property="createTime" />
<result column="updateTime" property="updateTime" />
<result column="del" property="del" />
</resultMap>
</mapper>

View File

@ -0,0 +1,18 @@
<?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="top.xinsin.mapper.PermissionsMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="top.xinsin.pojo.Permissions">
<id column="id" property="id" />
<result column="permission_name" property="permissionName" />
<result column="permission_code" property="permissionCode" />
<result column="description" property="description" />
<result column="account_id" property="accountId" />
<result column="create_time" property="createTime" />
<result column="update_time" property="updateTime" />
<result column="status" property="status" />
<result column="del" property="del" />
</resultMap>
</mapper>

View File

@ -0,0 +1,17 @@
<?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="top.xinsin.mapper.RolesMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="top.xinsin.pojo.Roles">
<id column="id" property="id" />
<result column="role_name" property="roleName" />
<result column="description" property="description" />
<result column="account_id" property="accountId" />
<result column="create_time" property="createTime" />
<result column="update_time" property="updateTime" />
<result column="status" property="status" />
<result column="del" property="del" />
</resultMap>
</mapper>

View File

@ -0,0 +1,73 @@
package top.xinsin;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
public class CodeGenerator {
public static void main(String[] args) {
List<String> tables = new ArrayList<>();
tables.add("account");
tables.add("roles");
tables.add("permissions");
FastAutoGenerator.create("jdbc:mysql://wzpmc.cn:3306/commerce_system?serverTimezone=UTC-8","commerce_system","Jix656dzD6St4YCn")
.globalConfig(builder -> {
builder.author("xinsin") //作者
.outputDir(System.getProperty("user.dir")+"\\src\\main\\java") //输出路径(写到java目录)
.enableSwagger() //开启swagger
.commentDate("yyyy-MM-dd")
.fileOverride(); //开启覆盖之前生成的文件
})
.packageConfig(builder -> {
builder.parent("top.xinsin")
.entity("pojo")
.service("service")
.serviceImpl("service.impl")
.controller("controller")
.mapper("mapper")
.xml("mapper")
.pathInfo(Collections.singletonMap(OutputFile.mapperXml,System.getProperty("user.dir")+"\\src\\main\\resources\\mapper"));
})
.strategyConfig(builder -> {
builder.addInclude(tables)
.serviceBuilder()
.formatServiceFileName("%sService")
.formatServiceImplFileName("%sServiceImpl")
.entityBuilder()
.enableLombok()
.logicDeleteColumnName("deleted")
.enableTableFieldAnnotation()
.controllerBuilder()
// 映射路径使用连字符格式而不是驼峰
.enableHyphenStyle()
.formatFileName("%sController")
.enableRestStyle()
.mapperBuilder()
//生成通用的resultMap
.enableBaseResultMap()
.superClass(BaseMapper.class)
.formatMapperFileName("%sMapper")
.enableMapperAnnotation()
.formatXmlFileName("%sMapper");
})
.templateConfig(new Consumer<TemplateConfig.Builder>() {
@Override
public void accept(TemplateConfig.Builder builder) {
// 实体类使用我们自定义模板
builder.entity("myentity.java");
}
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板默认的是Velocity引擎模板
.execute();
}
}

View File

@ -0,0 +1,201 @@
package top.xinsin;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.Test;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;
@SuppressWarnings("resource")
public class MainTest {
@Test
public void test01(){
System.out.println(new BCryptPasswordEncoder().encode(DigestUtils.md5Hex("xinsin")));
System.out.println(DigestUtils.md5Hex("xinsin"));
}
public static void main(String[] args) throws ClassNotFoundException, SQLException {
MainTest m = new MainTest();
Scanner sc = new Scanner(System.in);
while(true) {
int ch = m.menu();
switch(ch) {
case 1:m.SelectAll();break;
case 2:
System.out.println("请输入需要添加的学生的数量:");
int n = sc.nextInt();
int countInsert = m.insertStudent(n);
if(countInsert==n) {
System.out.println("学生信息添加成功!");
}else {
System.out.println("信息输入有误,学生添加失败。");
}
break;
case 3:
System.out.println("请输入需要修改的学生的学号:");
String IDUpdate= sc.next();
int countUpdate = m.updateStudent(IDUpdate);
if(countUpdate>0) {
System.out.println("学生信息修改成功。");
}
break;
case 4:
System.out.println("请输入需要删除的学生的学号:");
String IDDelete = sc.next();
int countDelete = m.deleteStudentByID(IDDelete);
if(countDelete>0) {
System.out.println("删除成功。");
}else {
System.out.println("删除失败。");
}
break;
case 5:System.out.println("感谢使用,系统退出中......");;System.exit(0);
default:System.err.println("请选择相应的功能......");
}
System.out.println("请输入回车键继续......");
sc.nextLine();
}
}
public int menu() {
Scanner sc = new Scanner(System.in);
System.out.println("******************************欢迎使用学生信息管理系统******************************");
System.out.println("\t\t功能列表如下");
System.out.println("\t\t1、查询学生信息。");
System.out.println("\t\t2、添加学生信息。");
System.out.println("\t\t3、修改学生信息。");
System.out.println("\t\t4、删除学生信息。");
System.out.println("\t\t5、退出系统。");
System.out.println("请选择你需要的功能:");
return sc.nextInt();
}
// 连接数据库
public Connection getConnection() throws SQLException, ClassNotFoundException {
String Driver = "com.mysql.cj.jdbc.Driver";
String url="jdbc:mysql://localhost:3306/StuIMS";
String user="root";
String pwd="123456";
Class.forName(Driver);
Connection con = DriverManager.getConnection(url,user,pwd);
if(con.isClosed()) {
System.err.println("数据库连接失败。");
return null;
}else {
System.out.println("连接成功。");
return con;
}
}
// 查询所有数据
public void SelectAll() throws ClassNotFoundException, SQLException {
Connection con = getConnection();
PreparedStatement ps = con.prepareStatement("select * from Student");
ResultSet rs = ps.executeQuery();
System.out.println(" 学号\t\t姓名\t 性别\t 生日\t\t学分");
while(rs.next()) {
System.out.println(rs.getString("studentID")+"\t"+rs.getString("studentName")+"\t "+rs.getString("studentSex")+"\t "
+rs.getString("studentBirthday")+"\t"+rs.getString("credit")+"\t");
}
}
// 插入数据
public int insertStudent(int num) throws ClassNotFoundException, SQLException {
Connection con = getConnection();
String sql = "insert into Student values(?,?,?,?,?,'202105')";
PreparedStatement ps = con.prepareStatement(sql);
Scanner sc = new Scanner(System.in);
int count=0;
for(int i=1;i<=num;i++) {
System.out.println("请输入第"+i+"个学生的学号:");
String ID = sc.next();
System.out.println("请输入第"+i+"个学生的姓名:");
String name = sc.next();
System.out.println("请输入第"+i+"个学生的性别:");
String sex = sc.next();
System.out.println("请输入第"+i+"个学生的生日:");
String birthday = sc.next();
System.out.println("请输入第"+i+"个学生的学分:");
int credit = sc.nextInt();
ps.setString(1, ID);
ps.setString(2, name);
ps.setString(3, sex);
ps.setString(4, birthday);
ps.setInt(5, credit);
if(ps.executeUpdate()>0) {
count++;
}else {
System.out.println("数据插入失败。");
break;
}
}
return count;
}
// 修改数据
public int updateStudent(String ID) throws ClassNotFoundException, SQLException {
Connection con = getConnection();
String sql="update Student set studentName=?,studentSex=?,studentBirthday=? where studentID="+ID;
PreparedStatement ps = con.prepareStatement(sql);
Scanner sc = new Scanner(System.in);
int count=0;
System.out.println("请输入学生的姓名:");
String name = sc.next();
System.out.println("请输入学生的性别:");
String sex = sc.next();
System.out.println("请输入学生的生日:");
String birthday = sc.next();
// System.out.println("请输入学生的学分:");
// int credit = sc.nextInt();
ps.setString(1, name);
ps.setString(2, sex);
ps.setString(3, birthday);
// ps.setInt(4, credit);
count = ps.executeUpdate();
return count;
}
public int deleteStudentByID(String ID) throws ClassNotFoundException, SQLException {
Connection con = getConnection();
Scanner sc = new Scanner(System.in);
PreparedStatement psS = con.prepareStatement("select * from Student where studentID="+ID);
ResultSet rs = psS.executeQuery();
System.out.println("即将删除的学生的信息:");
System.out.println(" 学号\t\t姓名\t 性别\t 生日\t\t学分");
while(rs.next()) {
System.out.println(rs.getString("studentID")+"\t"+rs.getString("studentName")+"\t "+rs.getString("studentSex")+"\t "
+rs.getString("studentBirthday")+"\t"+rs.getString("credit")+"\t");
}
System.out.println("请确认信息是否无误y/Y");
char ch1 = sc.next().charAt(0);
if(ch1=='Y'||ch1=='y') {
System.out.println("请确认是否删除y/Y?");
char ch2 = sc.next().charAt(0);
if(ch2=='y'||ch2=='Y') {
PreparedStatement psD = con.prepareStatement("delete from Student where studentID="+ID);
int count = psD.executeUpdate();
return count;
}else {
System.out.println("删除取消。");
return -1;
}
}else {
System.out.println("信息有误,请重新选择......");
return -1;
}
}
}

View File

@ -0,0 +1,135 @@
package ${package.Entity};
<#list table.importPackages as pkg>
import ${pkg};
</#list>
<#if entityLombokModel>
import lombok.Data;
<#if chainModel>
import lombok.experimental.Accessors;
</#if>
</#if>
/**
* <p>
* ${table.comment!}
* </p>
*
* @author ${author}
* @since ${date}
*/
<#if entityLombokModel>
@Data
<#if chainModel>
@Accessors(chain = true)
</#if>
</#if>
<#if table.convert>
@TableName("${schemaName}${table.name}")
</#if>
<#if superEntityClass??>
public class ${entity} extends ${superEntityClass}<#if activeRecord><${entity}></#if> {
<#elseif activeRecord>
public class ${entity} extends Model<${entity}> {
<#elseif entitySerialVersionUID>
public class ${entity} implements Serializable {
<#else>
public class ${entity} {
</#if>
<#if entitySerialVersionUID>
private static final long serialVersionUID = 1L;
</#if>
<#-- ---------- BEGIN 字段循环遍历 ---------->
<#list table.fields as field>
<#if field.keyFlag>
<#assign keyPropertyName="${field.propertyName}"/>
</#if>
<#if field.keyFlag>
<#-- 主键 -->
<#if field.keyIdentityFlag>
@TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
<#elseif idType??>
@TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
<#elseif field.convert>
@TableId("${field.annotationColumnName}")
</#if>
<#-- 普通字段 -->
<#elseif field.fill??>
<#-- ----- 存在字段填充设置 ----->
<#if field.convert>
@TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
<#else>
@TableField(fill = FieldFill.${field.fill})
</#if>
<#elseif field.convert>
@TableField("${field.annotationColumnName}")
</#if>
<#-- 乐观锁注解 -->
<#if field.versionField>
@Version
</#if>
<#-- 逻辑删除注解 -->
<#if field.logicDeleteField>
@TableLogic
</#if>
private ${field.propertyType} ${field.propertyName};
</#list>
<#------------ END 字段循环遍历 ---------->
<#if !entityLombokModel>
<#list table.fields as field>
<#if field.propertyType == "boolean">
<#assign getprefix="is"/>
<#else>
<#assign getprefix="get"/>
</#if>
public ${field.propertyType} ${getprefix}${field.capitalName}() {
return ${field.propertyName};
}
<#if chainModel>
public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
<#else>
public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
</#if>
this.${field.propertyName} = ${field.propertyName};
<#if chainModel>
return this;
</#if>
}
</#list>
</#if>
<#if entityColumnConstant>
<#list table.fields as field>
public static final String ${field.name?upper_case} = "${field.name}";
</#list>
</#if>
<#if activeRecord>
@Override
public Serializable pkVal() {
<#if keyPropertyName??>
return this.${keyPropertyName};
<#else>
return null;
</#if>
}
</#if>
<#if !entityLombokModel>
@Override
public String toString() {
return "${entity}{" +
<#list table.fields as field>
<#if field_index==0>
"${field.propertyName}=" + ${field.propertyName} +
<#else>
", ${field.propertyName}=" + ${field.propertyName} +
</#if>
</#list>
"}";
}
</#if>
}