创建springboot项目
配置环境
-
JDK1.8
-
maven版本为3.6.1
-
mysql5.7
-
redis6.2.7
后端结构
├─db #项目初始化SQL脚本 ├─src │ ├─main │ │ ├─java │ │ │ ├─com.···.··· │ │ │ │ ├─common #通用包 │ │ │ │ │ ├─aop #切面管理,用于获取日志和权限控制 │ │ │ │ │ ├─config #配置管理 │ │ │ │ │ ├─constant #常量管理 │ │ │ │ │ ├─data #公共数据管理 │ │ │ │ │ ├─exception #全局异常处理 │ │ │ │ │ ├─utils #工具类管理 │ │ │ │ ├─controller #控制层 │ │ │ │ ├─entity #实体类 │ │ │ │ ├─mapper #dao层 │ │ │ │ ├─service #服务层 │ │ │ │ ├─···Application #启动类(入口) │ │ │ ├─resource #资源 │ ├─test #测试 ├─pom #依赖配置
数据库导入
讲一下代码保存为可执行sql文件,通过idea自带或者其他工具导入数据库
/* Navicat MySQL Data Transfer Source Server : 175.178.78.181 Source Server Version : 50740 Source Host : 175.178.78.181:3306 Source Database : travel Target Server Type : MYSQL Target Server Version : 50740 File Encoding : 65001 Date: 2024-02-02 21:38:16 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for file -- ---------------------------- DROP TABLE IF EXISTS `file`; CREATE TABLE `file` ( `id` varchar(225) NOT NULL COMMENT '唯一id', `url` varchar(225) NOT NULL COMMENT '文件地址', `name` varchar(50) NOT NULL COMMENT '文件名', `type` varchar(100) NOT NULL COMMENT '文件类型', `create_by` varchar(50) NOT NULL COMMENT '创建者', `if_private` int(11) NOT NULL DEFAULT '0' COMMENT '是否私有(0不私有,1私有)', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='文件表'; DROP TABLE IF EXISTS `permission`; CREATE TABLE `permission` ( `id` bigint(20) NOT NULL COMMENT '唯一性id', `description` varchar(225) DEFAULT NULL COMMENT '权限描述', `expression` varchar(225) NOT NULL COMMENT '权限表达式', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ---------------------------- -- Records of permission -- ---------------------------- INSERT INTO `permission` VALUES ('1', '添加权限', 'ADD_PERMISSION'); INSERT INTO `permission` VALUES ('2', '删除权限', 'DELETE_PERMISSION'); INSERT INTO `permission` VALUES ('3', '修改权限', 'UPDATE_PERMISSION'); INSERT INTO `permission` VALUES ('4', '查询权限', 'READ_PERMISSION'); -- ---------------------------- -- Table structure for role -- ---------------------------- DROP TABLE IF EXISTS `role`; CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一id', `name` varchar(50) NOT NULL COMMENT '角色名', `description` varchar(225) DEFAULT NULL COMMENT '角色描述', `permission_ids` varchar(225) DEFAULT NULL COMMENT '权限ids', PRIMARY KEY (`id`), UNIQUE KEY `role_pk` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=690 DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; -- ---------------------------- -- Records of role -- ---------------------------- INSERT INTO `role` VALUES ('1', 'superAdmin', '超级管理员', '1,2,3,4'); INSERT INTO `role` VALUES ('2', 'admin', '管理员', '3,4'); INSERT INTO `role` VALUES ('3', 'user', '用户', '1,2,3,4'); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` varchar(20) NOT NULL COMMENT '唯一id', `account` varchar(20) NOT NULL COMMENT '账号', `phone` varchar(11) DEFAULT NULL COMMENT '电话', `email` varchar(30) DEFAULT NULL COMMENT '邮箱', `password` varchar(20) NOT NULL COMMENT '密码', `gender` smallint(6) DEFAULT NULL COMMENT '性别(男性为0女性为1)', `age` int(11) DEFAULT NULL, `birth` date DEFAULT NULL COMMENT '出生日期', `role_id` int(11) DEFAULT NULL COMMENT '角色表id', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '是否启用(1为启用,0为不启用)', `create_date` date NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `user_pk_account` (`account`), UNIQUE KEY `user_pk_phone` (`phone`), UNIQUE KEY `user_pk_email` (`email`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES ('1', 'superAdmin', '15912365485', '11598524568@qq.com', '123456', '0', '20', '2023-12-30', '1', '1', '2023-12-30');
依赖配置
在pom.xml中cv进一下配置
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.6</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.travel.term</groupId> <artifactId>travel-system</artifactId> <version>0.0.1-SNAPSHOT</version> <name>travel-system</name> <description>travel-system</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- fastjson工具类 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.79</version> </dependency> <!-- boot 基本依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--AOP--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--Lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- 数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.15</version> </dependency> <!-- MybatisPlus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <!-- Mysql --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.31</version> </dependency> <!-- Hutool --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.10</version> </dependency> <!-- Redis--> <dependency> <groupId>org.springframework.integration</groupId> <artifactId>spring-integration-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- Redis扩展--> <dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.18.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <!--springdoc 官方Starter--> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.6.6</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.4.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- 图片识别Tesseract OCR --> <dependency> <groupId>net.sourceforge.tess4j</groupId> <artifactId>tess4j</artifactId> <version>4.5.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
代码编写(本代码的包导入无写入,根据自己的项目包路径导入即可,idea快捷键导入)
yml
server: port: 8848 servlet: context-path: / #根路径地址 tomcat: uri-encoding: UTF-8 # Tomcat编码 threads: max: 1000 # 线程池最大线程数 min-spare: 30 #最小空闲线程数量 max-swallow-size: -1 #表示没限制最大请求体大小 shutdown: graceful # 关闭服务器时:先等待正在处理的请求完成再关闭 spring: # 数据库 datasource: url: jdbc:mysql://localhost:3306/travel?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC username: root password: Tpassword type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.mysql.cj.jdbc.Driver druid: filter: wall: config: multi-statement-allow: true #允许执行多条SQL语句 hikari: max-lifetime: 60000 # 连接的最大生命周期(ms) maximum-pool-size: 1000 # 连接池的最大连接数 # redis redis: host: localhost database: 0 port: 6379 timeout: 3S password: password # 文件上传配置 ## MULTIPART (MultipartProperties) # 开启 multipart 上传功能 servlet: multipart: enabled: true # 文件写入磁盘的阈值 file-size-threshold: 2KB # 最大文件大小 max-file-size: 200MB # 最大请求大小 max-request-size: 215MB # 文件存储所需参数 # 所有通过 REST API 上传的文件都将存储在此目录下 upload: path: C:/travel #返回json的全局时间格式 jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 # mybatisplus 配置 mybatis-plus: # Mybatis-Plus逻辑删除 global-config: db-config: logic-delete-value: 1 logic-not-delete-value: 0 mapper-locations: classpath*:mapper/*.xml # mybatis xml文件位置 configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl logging: level: # 设置日志级别 root: info file: path: logs logback: rollingpolicy: #日志滚动策略 max-history: 2000 #最大历史文件数量 max-file-size: 5MB #单个日志文件最大大小 #分页设置 pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true pageSizeZero: false #pageSize=0 返回所有 params: count=countSql # 密钥 encrypt: # 密钥 key: 510463728 # 接口api apis: # api放行白名单 paths: whites: - /authorization/** #swaggerapi路径配置 business: - /authorization/** # 上传下载配置 upload-download: multipart: # 文件上传的最大值 max-file-size: 512MB # 文件请求的最大值 max-request-size: 512MB # 文件存储路径 location: C:/travel
common通用层
aop:
MyInterceptor类:
拦截请求并打印请求信息,同时设置请求拦截除非白名单中有该请求路径否则不放行,具体可见代码:
import com.travel.term.common.data.properties.PathsProperties; import com.travel.term.common.data.resultAndReq.Result; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.util.AntPathMatcher; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.UUID; /** * AOP 类 */ @Aspect @Component @Slf4j public class MyInterceptor { @Resource private PathsProperties pathsProperties; private final AntPathMatcher pathMatcher = new AntPathMatcher(); /** * 拦截所有请求,打印请求信息 */ @Around("execution(* com.travel.term.controller.*.*(..))") public Object doLogInterceptor(ProceedingJoinPoint point) throws Throwable { // 计时 StopWatch stopWatch = new StopWatch(); stopWatch.start(); // 获取请求路径 RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); HttpServletRequest httpServletRequest = ((ServletRequestAttributes) requestAttributes).getRequest(); // 生成请求唯一 id String requestId = UUID.randomUUID().toString(); String url = httpServletRequest.getRequestURI(); // 获取请求参数 Object[] args = point.getArgs(); String reqParam = "[" + StringUtils.join(args, ", ") + "]"; // 输出请求日志 log.info("request start,id: {}, path: {}, ip: {}, params: {}", requestId, url, httpServletRequest.getRemoteHost(), reqParam); // 执行原方法 Object result = point.proceed(); // 输出响应日志 stopWatch.stop(); long totalTimeMillis = stopWatch.getTotalTimeMillis(); log.info("request end, id: {}, cost: {}ms", requestId, totalTimeMillis); return result; } /** * 权限控制 * * @param joinPoint * @return * @throws Throwable */ @Around("execution(* com.travel.term.controller.*.*(..))") public Object doPermissionInterceptor(ProceedingJoinPoint joinPoint) throws Throwable { // 获取请求头信息 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String uri = request.getRequestURI().toString(); String actualHeaderValue = request.getHeader("token"); // 有token放行,没有token不得访问,除白名单外 if (actualHeaderValue != null && !actualHeaderValue.isEmpty()) { //执行原方法 return joinPoint.proceed(); } else { // 判断是否为白名单路径,是则放行,否则拦截 for (String white : pathsProperties.getWhites()) { if (pathMatcher.match(white, uri)) { return joinPoint.proceed(); } } return Result.fail("无操作权限!!"); } } }
PermissionAspect类
注解拦截判断是否能够执行被注解标注的方法,具体见代码:
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.travel.term.common.exception.CommonException; import com.travel.term.common.utils.StringUtils; import com.travel.term.entity.Permission; import com.travel.term.entity.Role; import com.travel.term.entity.User; import com.travel.term.service.PermissionService; import com.travel.term.service.RoleService; import com.travel.term.service.UserService; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.List; import java.util.stream.Collectors; @Aspect @Component @Slf4j public class PermissionAspect { @Resource private UserService userService; @Resource private RoleService roleService; @Resource private PermissionService permissionService; /** * 目标方法 */ @Pointcut("@annotation(com.travel.term.common.aop.RequestPermission)") private void permission() { } /** * 目标方法调用之前执行 */ @Before("permission()") public void doBefore() { System.out.println("================== step 2: before =================="); } /** * 目标方法调用之后执行 */ @After("permission()") public void doAfter() { System.out.println("================== step 4: after =================="); } /** * 每次请求接口进行权限校验 * * @param joinPoint * @return * @throws Throwable */ @Around("permission()") public Object doPermissionInterceptor(ProceedingJoinPoint joinPoint) throws Throwable { // 获取请求头信息 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String actualHeaderValue = request.getHeader("token"); // 对token进行判断 if (actualHeaderValue == null) { throw new CommonException("您没有访问权限或者没有登录!"); } if (actualHeaderValue.contains("superAdmin")) { // 超管,放行 return joinPoint.proceed(); } else { // 不是超管,进行权限验证 //token切割 String[] role = actualHeaderValue.split("-"); //获取token中的用户id String id = role[role.length - 1]; String permission = role[role.length - 2]; return checkPermission(joinPoint, id, permission); } } private Object checkPermission(ProceedingJoinPoint joinPoint, String id, String use) throws Throwable { Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); RequestPermission permission = method.getAnnotation(RequestPermission.class); String name = permission.name(); // 查询权限列表 LambdaQueryWrapper<Permission> queryWrapper = new LambdaQueryWrapper<>(); //查询所有权限 User user = userService.getById(id); Role role; if (StringUtils.nullOrEmpty(user) || StringUtils.nullOrEmpty(role = (roleService.getById(user.getRoleId())))) { throw new CommonException("账号异常,请联系管理员"); } //切割获取ids String[] roleIds = role.getPermissionIds().split(","); //查询 queryWrapper.in(Permission::getId, roleIds); List<Permission> list = permissionService.list(queryWrapper); List<String> collect = list.stream().map((expression) -> expression.getExpression()).collect(Collectors.toList()); System.out.println(collect); // 判断 if (!collect.contains(name) && (collect.stream().filter(item -> (use + ":" + item).equals(name))).collect(Collectors.toList()).size() == 0) { throw new CommonException("您没有权限操作"); } return joinPoint.proceed(); } }
RequestPermission注解
自定义权限控制注解,注解方法为以上PermissionAspect类中方法,可自行修改,本例写的比较简单,可根据项目需要修改编写:
import com.travel.term.common.constant.PermissionConstant; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented // 在生成javac时显示该注解的信息 public @interface RequestPermission { //设置一个权限名称,默认为读权限 String name() default PermissionConstant.READ; }
config
CorsConfig类:
用于设置资源共享
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * 全局跨域配置 */ @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { // 覆盖所有请求 registry.addMapping("/**") // 允许发送 Cookie .allowCredentials(true) // 放行哪些域名(必须用 patterns,否则 * 会和 allowCredentials 冲突) .allowedOriginPatterns("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("*"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/api/file/**").addResourceLocations("file:" + "C:/travel"); } }
MyBatisPlusConfig类
mybatisplus配置类
import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * MyBatis Plus 配置 */ @Configuration @MapperScan("com.travel.term.mapper") public class MyBatisPlusConfig { /** * 拦截器配置 * * @return */ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); // 分页插件 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
RedisConfig类:
redis配置类
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } }
SpringDocConfig类
api文档(swagger配置)
/** * SpringDoc API文档相关配置 * Created by macro on 2022/3/4. */ @Configuration @Slf4j public class SpringDocConfig { @Resource private PathsProperties pathsProperties; @Bean public OpenAPI mallTinyOpenAPI() { return new OpenAPI() .info(new Info().title("旅游管理") .description("SpringDoc API 演示") .version("v1.0.0") .license(new License().name("Apache 2.0").url(""))) .externalDocs(new ExternalDocumentation() .description("travel") .url("")) .schemaRequirement("Authorization", this.securityScheme()); } private SecurityScheme securityScheme() { SecurityScheme securityScheme = new SecurityScheme(); //类型 securityScheme.setType(SecurityScheme.Type.APIKEY); //请求头的name securityScheme.setName("token"); //token所在未知 securityScheme.setIn(SecurityScheme.In.HEADER); return securityScheme; } /** * 用户管理 * * @return */ @Bean public GroupedOpenApi userApi() { return GroupedOpenApi.builder() .group("user用户管理API") .pathsToMatch("/user/**", "/role/**", "/permission/**") .build(); } /** * 业务管理 * * @return */ @Bean public GroupedOpenApi CrudApi() { return GroupedOpenApi.builder() .group("旅游管理接口") .pathsToMatch(StringUtils.listToArray(pathsProperties.getBusiness())) .build(); } }
constant
Constants类:
用于返回数据时的code
public class Constants { public static final int SUCCESS = 200; public static final int FAIL = 500; }
DefaultErrorResultConstant类
异常代码:
import com.travel.term.common.data.handle.ErrorResult; public class DefaultErrorResultConstant { public static final ErrorResult SYSTEM_ERROR = new ErrorResult("500", "系统异常"); public static final ErrorResult CUSTOM_ERROR = new ErrorResult("C99999", "自定义异常"); public static final ErrorResult MYBATIS_PLUS_ERROR = new ErrorResult("S00008", "数据库操作业务异常"); public static final ErrorResult NUMBER_FORMAT_ERROR = new ErrorResult("S00009", "数字转化异常"); public static final ErrorResult HTTP_ERROR = new ErrorResult("S00009", "请求异常,请检查"); public static final ErrorResult NULL_POINT = new ErrorResult("S00010", "空指针异常,请检查"); }
PermissionConstant类
权限常量,对应数据库
public class PermissionConstant { /** * 查看权限 */ public final static String READ = "READ_PERMISSION"; /** * 添加权限 */ public final static String ADD = "ADD_PERMISSION"; /** * 修改权限 */ public final static String DELETE = "DELETE_PERMISSION"; /** * 删除权限 */ public final static String UPDATE = "UPDATE_PERMISSION"; }
RoleConstant类
public class RoleConstant { public static final Integer 超管 = 1; public static final Integer 管理员 = 2; public static final Integer 用户 = 3; }
data
handle.ErrorResult:
异常数据,,包含错误码和报错消息,用于代码报错或者返回失败结果时使用
import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ErrorResult implements Serializable { private static final long serialVersionUID = -8738363760223125457L; /** * 错误码 */ private String code; /** * 错误消息 */ private String msg; public static ErrorResult build(ErrorResult commonErrorResult, String msg) { return new ErrorResult(commonErrorResult.getCode(), commonErrorResult.getMsg() + " " + msg); } }
properties.FileProperties
读取配置文件中有关文件存储的数据
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @ConfigurationProperties(prefix = "upload-download.multipart") @Data public class FileProperties { private String maxFileSize; private String maxRequestSize; private String location; }
properties.PathsProperties
读取配置文件中有关路径(swagger路径和白名单数据)的数据
import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import java.util.ArrayList; import java.util.List; /** * @author: cai * @description: api配置路径 * @date: 2023/12/11 */ @Configuration @ConfigurationProperties(prefix = "apis.paths") @Data public class PathsProperties { //白名单 private List<String> whites = new ArrayList<>(); // 业务接口 private List<String> business = new ArrayList<>(); }
resultAndReq.PageResult
分页结果返回对象
import com.github.pagehelper.PageInfo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.io.Serializable; import java.util.List; @Data @Schema(name="PageResult",description ="分页结果" ) public class PageResult<T> implements Serializable { @Schema(name="pageNum",description ="第几页" ) private int pageNum; @Schema(name="pageSize",description ="每页条数" ) private int pageSize; @Schema(name="pages",description ="总页数" ) private int pages; @Schema(name="total",description ="总条数" ) private long total; @Schema(name="records",description ="数据结果" ) private List<T> records; public PageResult() { } /** * 通过pageHelper中的pageInfo进行包装 * * @param list */ public PageResult(List<T> list) { PageInfo pageInfo = new PageInfo<>(list); this.setRecords(pageInfo.getList()); this.setPageNum(pageInfo.getPageNum()); this.setPageSize(pageInfo.getPageSize()); this.setPages(pageInfo.getPages()); this.setTotal(pageInfo.getTotal()); } /** * 外部计算直接包装分页 * * @param list * @param pageNum * @param pageSize * @param total */ public PageResult(List<T> list, int pageNum, int pageSize, long total) { int pages = (int) (total / pageSize); pages = total % pageSize != 0 ? pages + 1 : pages; this.setRecords(list); this.setPageNum(pageNum); this.setPageSize(pageSize); this.setPages(pages); this.setTotal(total); } }
resultAndReq.ReqPage:
分页接口接收分页数据对象类
import java.io.Serializable; public class ReqPage implements Serializable { private Integer pageNum = 1; private Integer pageSize = 10; public Integer getPageNum() { return pageNum; } public ReqPage setPageNum(Integer pageNum) { if (pageNum == null) { return this; } this.pageNum = pageNum; return this; } public Integer getPageSize() { return pageSize; } public ReqPage setPageSize(Integer pageSize) { if (pageNum == null) { return this; } this.pageSize = pageSize; return this; } }
resultAndReq.Result
非分页接口数据返回对象类
import com.travel.term.common.constant.Constants; import lombok.Data; import lombok.experimental.Accessors; import java.io.Serializable; import java.util.HashMap; import java.util.Map; @Accessors(chain = true) @Data public class Result<T> implements Serializable { private static final long serialVersionUID = 1L; private boolean success = true; private int code = Constants.SUCCESS; private String msg; private T data; private Map<String, String> param = new HashMap<>(); public static <T> Result<T> buildResult(T data, int code, String msg) { return new Result<T>().setCode(code).setData(data).setMsg(msg).setSuccess(code == Constants.SUCCESS ? true : false); } public static <T> Result<T> success() { return buildResult(null, Constants.SUCCESS, null); } public static <T> Result<T> success(String msg) { return buildResult(null, Constants.SUCCESS, msg); } public static <T> Result<T> success(T data) { return buildResult(data, Constants.SUCCESS, null); } public static <T> Result<T> success(T data, String msg) { return buildResult(data, Constants.SUCCESS, msg); } public static <T> Result<T> fail() { return buildResult(null, Constants.FAIL, null); } public static <T> Result<T> fail(String msg) { return buildResult(null, Constants.FAIL, msg); } public static <T> Result<T> fail(T data) { return buildResult(data, Constants.FAIL, null); } public static <T> Result<T> fail(T data, String msg) { return buildResult(data, Constants.FAIL, msg); } public static <T> Result<T> fail(int code, String msg) { return buildResult(null, code, msg); } }
exception.CommonException
自定义异常
import com.travel.term.common.data.handle.ErrorResult; import lombok.Data; import lombok.EqualsAndHashCode; @EqualsAndHashCode(callSuper = true) @Data public class CommonException extends RuntimeException { protected ErrorResult errorResult; public CommonException(String message) { super(message); } public CommonException(String message, Throwable cause) { super(message, cause); } public CommonException(Throwable cause) { super(cause); } protected CommonException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } public CommonException(String code, String msg) { super(msg + "(" + code + ")"); this.errorResult = new ErrorResult(code, msg); } public CommonException(ErrorResult errorResult) { super(errorResult.getMsg() + "(" + errorResult.getCode() + ")"); this.errorResult = errorResult; } }
exception.GlobalExceptionHandler
全局异常处理
import cn.hutool.http.HttpException; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.travel.term.common.constant.DefaultErrorResultConstant; import com.travel.term.common.data.handle.ErrorResult; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { /** * 通用业务异常 * * @param e * @return */ @ExceptionHandler(value = CommonException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResult handleCommonException(CommonException e) { log.error("{}, {}", e.getMessage(), e); if (e.getErrorResult() != null) { return e.getErrorResult(); } return new ErrorResult(DefaultErrorResultConstant.CUSTOM_ERROR.getCode(), e.getMessage()); } /** * 其他运行时异常 * @param e * @return */ @ExceptionHandler(value = Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResult handleDefaultException(Exception e) { log.error("{}, {}", e.getMessage(), e); return DefaultErrorResultConstant.SYSTEM_ERROR; } /** * 其mybatis-plus异常 * @param e * @return */ @ExceptionHandler(value = MybatisPlusException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResult handleMybatisException(Exception e) { log.error("{}, {}", e.getMessage(), e); return DefaultErrorResultConstant.MYBATIS_PLUS_ERROR; } /** * 数字格式化异常 * @param e * @return */ @ExceptionHandler(value = NumberFormatException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResult handleNumberException(Exception e) { log.error("{}, {}", e.getMessage(), e); return DefaultErrorResultConstant.NUMBER_FORMAT_ERROR; } @ExceptionHandler(value = HttpException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResult handleHttpException(Exception e) { log.error("{}, {}", e.getMessage(), e); return DefaultErrorResultConstant.HTTP_ERROR; } @ExceptionHandler(value = NullPointerException.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ErrorResult handleNullPointerException(Exception e) { log.error("{}, {}", e.getMessage(), e); return DefaultErrorResultConstant.NULL_POINT; } }
utils
EncryptUtils工具类
密码加密和解密
import com.travel.term.common.exception.CommonException; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @Configuration public class EncryptUtils { private static Integer key; @Value("${encrypt.key}") public void setKey(Integer key) { EncryptUtils.key = key; } /** * 解密 * * @param str */ public static String decrypt(String str) { if (StringUtils.nullOrEmpty(str)){ throw new CommonException("没有设置密码或者密码为空!"); } //解密 int k = Integer.parseInt("-" + key); String content = ""; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c >= 'a' && c <= 'z')//如果字符串中的某个字符是小写字母 { c += k % 26;//移动key%26位 if (c < 'a') c += 26;//向左超界 if (c > 'z') c -= 26;//向右超界 } else if (c >= 'A' && c <= 'Z')//如果字符串中的某个字符是大写字母 { c += k % 26;//移动key%26位 if (c < 'A') c += 26;//向左超界 if (c > 'Z') c -= 26;//向右超界 } content += c;//将解密后的字符连成字符串 } return content; } /** * 加密 * * @param str */ public static String kaisaEncrypt(String str) { //加密 String encryptResult = ""; for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (c >= 'a' && c <= 'z')//如果字符串中的某个字符是小写字母 { c += key % 26;//移动key%26位 if (c < 'a') c += 26;//向左超界 if (c > 'z') c -= 26;//向右超界 } else if (c >= 'A' && c <= 'Z')//如果字符串中的某个字符是大写字母 { c += key % 26;//移动key%26位 if (c < 'A') c += 26;//向左超界 if (c > 'Z') c -= 26;//向右超界 } encryptResult += c;//将加密后的字符连成字符串 } return encryptResult; } }
FileUtils
文件操作工具类
import java.io.File; public class FileUtils { public static boolean deleteFile(String path) { File file = new File(path); if (!file.exists()) { return false; } return file.delete(); } }
StringUtils
字符串工具类
import java.util.List; public class StringUtils { /** * 将集合转为数组 */ public static String[] listToArray(List<String> list) { String[] result = new String[list.size()]; for (int i = 0; i < list.size(); i++) { result[i] = list.get(i); } return result; } public static Boolean nullOrEmpty(String... args) { for (String arg : args) { if (arg == "" || arg == null) { return true; } } return false; } public static Boolean nullOrEmpty(Object o) { return o == null ? true : o instanceof String ? ((String) o).isEmpty() : false; } }
controller层
其中的OrcController为图片识别,不在这里写出,需要可到我主页的文章中寻找(,TourismController为我本项目的接口,不在这里写出)
Authorization
登录接口
import cn.hutool.core.lang.UUID; import com.travel.term.common.exception.CommonException; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.common.utils.StringUtils; import com.travel.term.entity.Role; import com.travel.term.entity.User; import com.travel.term.entity.req.ReqLoginUser; import com.travel.term.service.RoleService; import com.travel.term.service.UserService; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController @RequestMapping("/authorization") @Tag(name = "登录接口", description = "登录接口信息数据,包括获取token") @Slf4j public class Authorization { @Resource private UserService userService; @Resource private RoleService roleService; @GetMapping("/login") public Result<String> login(ReqLoginUser loginUserVo) { //检查账号密码是否存在并正确 User user = userService.checkUserInfo(loginUserVo); if (!StringUtils.nullOrEmpty(user)) { if (user.getId().equals("-1")) { return Result.fail("没有该账号"); } if (user.getStatus() == 0) { return Result.fail("该账号已被禁用,请联系管理员!"); } return Result.success(user.getId(), "登录成功!"); } return Result.fail("账号或密码错误!"); } @GetMapping("/token/{id}") public Result<String> buildToken(@PathVariable("id") String id) { // id解密 // String newId = EncryptUtils.decrypt(id); // 获取角色 log.info(id); User user = userService.getById(id); log.info(user.toString()); if (StringUtils.nullOrEmpty(user)) { throw new CommonException("账号异常,请联系管理员"); } // 账号检测通过,获取角色 Role role = roleService.getById(user.getRoleId()); String token = buildToken(role.getName(), user.getId()); return Result.success(token, "获取token为" + token); } private String buildToken(String role, String id) { // uuid和角色名称和用户id组成token return UUID.randomUUID() + "-" + role + "-" + id; } }
IFileController
文件接口,操作文件
import com.github.pagehelper.PageHelper; import com.travel.term.common.aop.RequestPermission; import com.travel.term.common.constant.PermissionConstant; import com.travel.term.common.data.resultAndReq.PageResult; import com.travel.term.common.data.resultAndReq.ReqPage; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.common.utils.StringUtils; import com.travel.term.entity.IFile; import com.travel.term.entity.req.ReqIFile; import com.travel.term.service.IFileService; import io.swagger.v3.oas.annotations.tags.Tag; import org.apache.tomcat.util.http.fileupload.IOUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.Calendar; import java.util.Date; import java.util.UUID; @RestController @Tag(name = "文件接口", description = "文件操作接口") @RequestMapping("/file") public class IFileController { @Resource private IFileService iFileService; @GetMapping @RequestPermission(name = ("admin:" + PermissionConstant.READ)) public Result<PageResult<IFile>> pageList(ReqPage reqPage, ReqIFile reqIFile) { PageHelper.startPage(reqPage.getPageNum(), reqPage.getPageSize()); return Result.success(iFileService.list(reqIFile), "查询成功"); } @PostMapping("/upload") public Result<IFile> uploadFile(ReqIFile reqIFile, MultipartFile multipartFiles) { File fileDir = iFileService.checkAddr(); IFile iFile = new IFile(); try { if (!StringUtils.nullOrEmpty(multipartFiles)) { // 创建时间作为路径 Date currentDate = new Date(); Calendar calendar = Calendar.getInstance(); calendar.setTime(currentDate); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) + 1; int day = calendar.get(Calendar.DAY_OF_MONTH); String uuid = UUID.randomUUID().toString().replaceAll("-", ""); // 保存 try { //以原来的名称命名,覆盖掉旧的,这里也可以使用UUID之类的方式命名,这里就没有处理了 String storagePath = fileDir.getAbsolutePath() + "/" + year + "/" + month + "/" + day + "/" + uuid + multipartFiles.getOriginalFilename().substring(multipartFiles.getOriginalFilename().lastIndexOf(".")); File file = new File(storagePath); if (!file.exists() && !file.isDirectory()) { file.mkdirs(); } System.out.println("上传的文件:" + multipartFiles.getName() + "," + multipartFiles.getContentType() + "," + multipartFiles.getOriginalFilename() + ",保存的路径为:" + storagePath); // 3种方法: 第1种 // Streams.copy(multipartFiles[i].getInputStream(), new FileOutputStream(storagePath), true); // 第2种 // Path path = Paths.get(storagePath); // Files.write(path, multipartFiles[i].getBytes()); // 第3种 multipartFiles.transferTo(file); } catch (IOException e) { e.printStackTrace(); } // 上传成功,保存文件信息 iFile.setId(uuid) .setUrl("/" + year + "/" + month + "/" + day + "/" + uuid + multipartFiles.getOriginalFilename().substring(multipartFiles.getOriginalFilename().lastIndexOf("."))) .setName(uuid + multipartFiles.getOriginalFilename().substring(multipartFiles.getOriginalFilename().lastIndexOf("."))) .setType(multipartFiles.getContentType()) .setIfPrivate(Integer.parseInt(reqIFile.getIfPrivate())) .setCreateBy(reqIFile.getCreateBy()); if (!iFileService.save(iFile)) { return Result.fail("上传失败!"); } } } catch (Exception e) { return Result.fail(e.getMessage()); } //前端可以通过状态码,判断文件是否上传成功 return Result.success(iFile, "上传成功"); } /** * @param id 文件标识 * @param response * @return */ @GetMapping("/download") public Result<IFile> downloadFile(@RequestParam String id, HttpServletResponse response) { // 查询是否存在该文件 IFile iFile = iFileService.getById(id); if (StringUtils.nullOrEmpty(iFile)) { return Result.fail("没有该文件"); } File fileDir = iFileService.checkAddr(); // 文件下载操作 OutputStream os = null; InputStream is = null; try { // 取得输出流 os = response.getOutputStream(); // 清空输出流 response.reset(); response.setContentType("application/x-download;charset=utf-8"); //Content-Disposition中指定的类型是文件的扩展名,并且弹出的下载对话框中的文件类型图片是按照文件的扩展名显示的,点保存后,文件以filename的值命名, // 保存类型以Content中设置的为准。注意:在设置Content-Disposition头字段之前,一定要设置Content-Type头字段。 //把文件名按UTF-8取出,并按ISO8859-1编码,保证弹出窗口中的文件名中文不乱码,中文不要太多,最多支持17个中文,因为header有150个字节限制。 response.setHeader("Content-Disposition", "attachment;filename=" + new String(iFile.getName().getBytes("utf-8"), "ISO8859-1")); //读取流 File f = new File(fileDir.getAbsolutePath() + iFile.getUrl()); is = new FileInputStream(f); if (is == null) { System.out.println("下载附件失败,请检查文件“" + iFile.getUrl() + "”是否存在"); return Result.fail("下载附件失败,请检查文件“" + iFile.getUrl() + "”是否存在"); } //复制 IOUtils.copy(is, response.getOutputStream()); response.getOutputStream().flush(); } catch (IOException e) { return Result.fail("下载附件失败,error:" + e.getMessage()); } //文件的关闭放在finally中 finally { try { if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (os != null) { os.close(); } } catch (IOException e) { e.printStackTrace(); } } //其实,这个返回什么都不重要 return Result.success(iFile, "下载成功"); } @DeleteMapping("/{id}") @RequestPermission(name = (PermissionConstant.DELETE)) public Result<Boolean> deleteFile(@PathVariable("id") String id) { if (StringUtils.nullOrEmpty(id)) { return Result.fail(false, "请注意选择要删除的文件"); } IFile file = iFileService.getById(id); String path = iFileService.checkAddr().getAbsolutePath() + (StringUtils.nullOrEmpty(file) ? "" : file.getUrl()); return iFileService.deleteFileByPath(file, path) ? Result.success(true, "删除成功") : Result.fail(false, "删除失败"); } }
PermissionController
权限接口
import com.travel.term.common.aop.RequestPermission; import com.travel.term.common.constant.PermissionConstant; import com.travel.term.common.data.resultAndReq.ReqPage; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.entity.Permission; import com.travel.term.service.PermissionService; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; /** * (Permission)表控制层 * * @author cai * @since 2023-12-14 12:33:49 */ @RestController @Tag(name = "权限接口信息", description = "权限接口信息") @RequestMapping("/permission") public class PermissionController { /** * 服务对象 */ @Resource private PermissionService permissionService; /** * 分页查询所有数据 * * @param page 分页对象 * @return 所有数据 */ @GetMapping @RequestPermission(name = ("admin:" + PermissionConstant.READ)) public Result<List<Permission>> selectAll(ReqPage page) { return Result.success((this.permissionService.list())); } }
RoleController
角色接口
import com.github.pagehelper.PageHelper; import com.travel.term.common.aop.RequestPermission; import com.travel.term.common.constant.PermissionConstant; import com.travel.term.common.data.resultAndReq.PageResult; import com.travel.term.common.data.resultAndReq.ReqPage; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.entity.Role; import com.travel.term.entity.req.ReqRole; import com.travel.term.service.RoleService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; /** * (User)表控制层 * * @author cai * @since 2023-12-13 */ @RestController @RequestMapping("/role") @Tag(name = "角色接口", description = "角色信息接口") @Slf4j public class RoleController { /** * 服务对象 */ @Resource private RoleService roleService; /** * 分页查询所有数据 * * @param page 分页对象 * @return 所有数据 */ @RequestPermission(name = ("admin:" + PermissionConstant.READ)) @Operation(summary = "返回所有分页信息", description = "") @GetMapping public Result<PageResult<Role>> selectAll(ReqPage page, ReqRole reqRole) { PageHelper.startPage(page.getPageNum(), page.getPageSize()); return Result.success(new PageResult<>(roleService.list(reqRole)), "查询成功"); } /** * 通过主键查询单条数据 * * @param id 主键 * @return 单条数据 */ @GetMapping("/{id}") @RequestPermission(name = PermissionConstant.READ) public Result<Role> selectOne(@PathVariable("id") String id) { return Result.success(roleService.getById(id), "查询成功"); } /** * 新增数据 * * @param role 实体对象 * @return 新增结果 */ @PostMapping @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ)) public Result<Boolean> insert(@RequestBody Role role) { return Result.success(roleService.save(role), "添加成功"); } /** * 修改数据 * * @param role 实体对象 * @return 修改结果 */ @PutMapping @RequestPermission(name = PermissionConstant.READ) public Result<Boolean> update(@RequestBody Role role) { return Result.success(roleService.updateById(role), "修改成功"); } /** * 删除数据 * * @param ids 主键集合 * @return 删除结果 */ @DeleteMapping("/batch/{ids}") @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ)) public Result<Boolean> batchDelete(@Parameter(description = "ids为路径参数,是由多个id以英文,分隔开的字符串") @PathVariable("ids") String ids) { String[] newIds = ids.split(","); return Result.success(roleService.removeByIds(Arrays.asList(newIds)), "删除成功"); } /** * 返回集合role * * @return */ @GetMapping("/backen/list") @RequestPermission(name = PermissionConstant.READ) public Result<List<Role>> getList() { List<Role> list = roleService.list(new ReqRole()).stream().filter(item -> item != null && !item.getId().equals("1")).collect(Collectors.toList()); return Result.success(list, "查询成功"); } /** * 根据id删除角色信息 * * @param id * @return */ @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ)) @DeleteMapping("/{id}") public Result<Boolean> delete(@PathVariable("id") Long id) { return roleService.deleteById(id) ? Result.success("删除成功") : Result.fail("删除失败"); } }
UserController
用户接口
import com.github.pagehelper.PageHelper; import com.travel.term.common.aop.RequestPermission; import com.travel.term.common.constant.PermissionConstant; import com.travel.term.common.data.resultAndReq.PageResult; import com.travel.term.common.data.resultAndReq.ReqPage; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.common.utils.EncryptUtils; import com.travel.term.common.utils.StringUtils; import com.travel.term.entity.Role; import com.travel.term.entity.User; import com.travel.term.entity.req.ReqUser; import com.travel.term.service.RoleService; import com.travel.term.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.Arrays; import java.util.List; /** * (User)表控制层 * * @author cai * @since 2023-12-04 22:02:00 */ @RestController @RequestMapping("/user") @Tag(name = "用户信息", description = "用户信息接口") @Slf4j public class UserController { /** * 服务对象 */ @Resource private UserService userService; @Resource private RoleService roleService; /** * 分页查询所有数据 * * @param page 分页对象 * @return 所有数据 */ @Operation(summary = "返回所有信息", description = "") @GetMapping @RequestPermission(name = ("admin:" + PermissionConstant.READ)) public Result<PageResult<User>> selectAll(ReqPage page, ReqUser reqUser) { PageHelper.startPage(page.getPageNum(), page.getPageSize()); return Result.success(userService.list(reqUser), "查询成功"); } /** * 通过主键查询单条数据 * * @param id 主键 * @return 单条数据 */ @GetMapping("/{id}") @RequestPermission(name = PermissionConstant.READ) public Result<User> selectOne(@PathVariable("id") String id) { User user = userService.getById(id); if (!StringUtils.nullOrEmpty(user)) { Role roleName = roleService.getById(user.getRoleId()); user.setRoleName(!StringUtils.nullOrEmpty(roleName) ? roleName.getName() : ""); } user.setPassword(EncryptUtils.decrypt(user.getPassword())); return Result.success(user, "查询成功"); } /** * 新增数据 * * @param user 实体对象 * @return 新增结果 */ @PostMapping @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ)) public Result<Boolean> insert(@RequestBody User user) { user.setPassword(EncryptUtils.kaisaEncrypt(user.getPassword())); return Result.success(userService.save(user), "添加成功"); } /** * 修改数据 * * @param user 实体对象 * @return 修改结果 */ @PutMapping @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ)) public Result<Boolean> update(@RequestBody User user) { if (user.getId().equals("1")) { return Result.fail("不允许下线超级管理员"); } user.setPassword(EncryptUtils.kaisaEncrypt(user.getPassword())); return Result.success(userService.updateById(user), "修改成功"); } /** * 删除数据 * * @param ids 主键集合 * @return 删除结果 */ @DeleteMapping("/batch/{ids}") @RequestPermission(name = ("superAdmin:" + PermissionConstant.READ)) public Result<Boolean> deleteBatch(@PathVariable("ids") String ids) { List<String> newIds = Arrays.asList(ids.split(",")); return Result.success(userService.removeByIds(newIds), "删除成功"); } /** * 根据id删除用户 * * @param id * @return */ @DeleteMapping("/{id}") public Result<Boolean> delete(@PathVariable("id") String id) { if (id.equals("1")) { return Result.fail("超级管理员不允许注销"); } return userService.removeById(id) ? Result.success("删除成功") : Result.fail("删除失败"); } /** * PC端用户注册 * * @param user * @return */ @PostMapping("/register") public Result<Boolean> register(@RequestBody User user) { System.out.println(user); return userService.register(user); } /** * 检测用户名手机号,邮箱是否重复 * * @param checkColumn * @return */ @GetMapping("/check") public Result<Boolean> check(String checkColumn) { return userService.checkInfo(checkColumn); } }
entity层
实体类对象层
req.ReqLoginUser
登陆接收数据实体类
import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Data @Schema(description = "", name = "登录接口接收参数") public class ReqLoginUser { @Schema(name = "account", description = "登陆账户,可为账号、手机号、邮箱号") private String account; @Schema(name = "password", description = "账户密码") private String password; }
req.ReqIFile
文件操作接收数据实体类
import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Schema(description = "role分页查询对象") @Data public class ReqIFile { @Schema(description = "创建者") private String createBy; @Schema(description = "是否私有(0不私有,1私有)") private String ifPrivate = String.valueOf(0); }
req.ReqRole
角色接收数据实体类
import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Schema(description="role分页查询对象") @Data public class ReqRole { @Schema(description = "角色名") private String name; @Schema(description = "权限ids,前端传过来应该是所需权限的id值的组合(多个id用英文字符,分割形成的字符串)") private String permissionIds; }
req.ReqUser
import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @Schema(description="user接收数据对象") @Data public class ReqUser { @Schema(description = "账号") private String account; @Schema(description = "电话") private String phone; @Schema(description = "邮箱地址") private String email; @Schema(description = "性别(男性为0女性为1)") private Integer gender; @Schema(description = "角色表id") private Integer roleId; @Schema(description = "状态,默认为1启动") private Integer status; }
IFile
import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** * 文件表(File)表实体类 * * @author cai * @since 2024-01-26 20:07:20 */ @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @Schema(description = "file对象") @Data @TableName("file") public class IFile { private static final long serialVersionUID = 1L; @Schema(description = "唯一id") private String id; @Schema(description = "文件地址") private String url; @Schema(description = "文件名") private String name; @Schema(description = "文件类型") private String type; @Schema(description = "创建者") private String createBy; @Schema(description = "是否私有(0不私有,1私有)") private Integer ifPrivate = 0; }
Permission
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** * (Permission)表实体类 * * @author cai * @since 2023-12-14 12:34:49 */ @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @Schema(description="Permission对象") @Data @TableName("permission") public class Permission { @Schema(description = "唯一id") @TableId(type = IdType.ASSIGN_ID) private Long id; @Schema(description = "描述") private String description; @Schema(description = "表达式") private String expression; }
Role
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 io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; /** * (Role)表实体类 * * @author cai * @since 2023-12-13 */ @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @Schema(description="role对象") @Data @TableName("role") public class Role { @Schema(description = "唯一id") @TableId(type = IdType.AUTO) private String id; @Schema(description = "角色名") private String name; @Schema(description = "角色描述") private String description; @Schema(description = "权限ids") private String permissionIds; @Schema(description = "前端权限名字渲染,不参与表的映射") @TableField(exist = false) private String permissionName; }
User
import java.util.Date; import cn.hutool.core.date.DateTime; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.experimental.Accessors; import org.springframework.format.annotation.DateTimeFormat; /** * (User)表实体类 * * @author cai * @since 2023-12-04 22:02:02 */ @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @Schema(description = "user对象") @Data @TableName("user") public class User { @Schema(description = "唯一id") @TableId(type = IdType.ASSIGN_ID) private String id; @Schema(description = "账号") private String account; @Schema(description = "电话") private String phone; @Schema(description = "邮箱地址") private String email; @Schema(description = "密码") private String password; @Schema(description = "性别(男性为0女性为1)") private Integer gender; @Schema(description = "年龄") private Integer age; @Schema(description = "出生日期") @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birth; @Schema(description = "角色表id") private Integer roleId; @Schema(description = "状态,默认为1启动") private Integer status = 1; @Schema(description = "创建时间") @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") @DateTimeFormat(pattern = "yyyy-MM-dd") private Date createDate = DateTime.now(); @TableField(exist = false) private String roleName; @Schema(description = "用户头像") private String avatar; }
mapper层
IFileMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.travel.term.entity.IFile; public interface IFileMapper extends BaseMapper<IFile> { }
PermissionMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.travel.term.entity.Permission; /** * (Permission)表数据库访问层 * * @author cai * @since 2023-12-14 12:34:20 */ public interface PermissionMapper extends BaseMapper<Permission> { }
RoleMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.travel.term.entity.Role; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.List; /** * (Role)表数据库访问层 * * @author cai * @since 2023-12-13 */ public interface RoleMapper extends BaseMapper<Role> { // @Select("select description from permission where id in (#{permissionIds})") List<String> queryIds(@Param("permissionIds") List<String> permissionIds); }
UserMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.travel.term.entity.Role; import com.travel.term.entity.User; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import java.util.Arrays; import java.util.List; /** * (User)表数据库访问层 * * @author cai * @since 2023-12-04 22:02:01 */ public interface UserMapper extends BaseMapper<User> { User checkAccount(@Param("account") String account); @Select("select * from role") List<Role> roleList(); }
service层
IFileService
import com.baomidou.mybatisplus.extension.service.IService; import com.travel.term.common.data.resultAndReq.PageResult; import com.travel.term.entity.IFile; import com.travel.term.entity.req.ReqIFile; import java.io.File; public interface IFileService extends IService<IFile> { File checkAddr(); PageResult<IFile> list(ReqIFile reqIFile); boolean deleteFileByPath(IFile file, String path); }
PermissionService
import com.baomidou.mybatisplus.extension.service.IService; import com.travel.term.entity.Permission; import com.travel.term.entity.Role; /** * (User)表服务接口 * * @author cai * @since 2023-12-04 22:02:03 */ public interface PermissionService extends IService<Permission> { }
RoleService
import com.baomidou.mybatisplus.extension.service.IService; import com.travel.term.entity.Role; import com.travel.term.entity.User; import com.travel.term.entity.req.ReqRole; import java.util.Arrays; import java.util.List; /** * (User)表服务接口 * * @author cai * @since 2023-12-04 22:02:03 */ public interface RoleService extends IService<Role> { Boolean deleteById(Long id); List<Role> list(ReqRole reqRole); }
UserService
import com.baomidou.mybatisplus.extension.service.IService; import com.travel.term.common.data.resultAndReq.PageResult; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.entity.User; import com.travel.term.entity.req.ReqUser; import com.travel.term.entity.req.ReqLoginUser; /** * (User)表服务接口 * * @author cai * @since 2023-12-04 22:02:03 */ public interface UserService extends IService<User> { User checkUserInfo(ReqLoginUser loginUserVo); Result<Boolean> register(User user); PageResult<User> list(ReqUser reqUser); Result<Boolean> checkInfo(String checkColumn); }
impl
IFileServiceImpl
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.travel.term.common.data.properties.FileProperties; import com.travel.term.common.data.resultAndReq.PageResult; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.common.exception.CommonException; import com.travel.term.common.utils.FileUtils; import com.travel.term.common.utils.StringUtils; import com.travel.term.entity.IFile; import com.travel.term.entity.User; import com.travel.term.entity.req.ReqIFile; import com.travel.term.mapper.IFileMapper; import com.travel.term.service.IFileService; import com.travel.term.service.UserService; import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.util.List; @Service public class IFileServiceImpl extends ServiceImpl<IFileMapper, IFile> implements IFileService { @Resource private FileProperties fileProperties; @Resource private UserService userService; /** * 检查当前操作系统 * * @return */ @Override public File checkAddr() { File fileDir = new File("C:/"); // 判断是否为windows系统 if (fileDir.exists()) { fileDir = new File("C:/travel"); } else { // 否则按照默认路径 fileDir = new File(fileProperties.getLocation()); } if (!fileDir.exists() && !fileDir.isDirectory()) { fileDir.mkdirs(); } return fileDir; } @Override public PageResult<IFile> list(ReqIFile reqIFile) { LambdaQueryWrapper<IFile> queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(!StringUtils.nullOrEmpty(reqIFile.getIfPrivate()), IFile::getIfPrivate, Integer.parseInt(reqIFile.getIfPrivate())) .like(!StringUtils.nullOrEmpty(reqIFile.getCreateBy()), IFile::getCreateBy, reqIFile.getCreateBy()); List<IFile> list = this.list(queryWrapper); PageResult<IFile> pageResult = new PageResult<>(list); return pageResult; } @Override public boolean deleteFileByPath(IFile file, String path) { // 获取请求头信息 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); String actualHeaderValue = request.getHeader("token"); //处理token获取用户id String[] split = actualHeaderValue.split("-"); String id = split[split.length - 1]; //通过id获取用户名 User user = userService.getById(id); if (StringUtils.nullOrEmpty(user)) { throw new CommonException("服务器出错,请稍后重试"); } //判断用户名和文件创建角色是否相同 if (!user.getAccount().equals(file.getCreateBy()) && file.getIfPrivate() != 0) { return false; } if (this.removeById(file.getId())) { if (!FileUtils.deleteFile(path)) { System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); this.save(file); return false; } return true; } return false; } }
PermissionServiceImpl
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.travel.term.entity.Permission; import com.travel.term.mapper.PermissionMapper; import com.travel.term.service.PermissionService; import org.springframework.stereotype.Service; /** * (User)表服务实现类 * * @author cai * @since 2023-12-13 */ @Service public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService { }
RoleServiceImpl
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.travel.term.common.utils.StringUtils; import com.travel.term.entity.Permission; import com.travel.term.entity.Role; import com.travel.term.entity.User; import com.travel.term.entity.req.ReqRole; import com.travel.term.mapper.RoleMapper; import com.travel.term.mapper.UserMapper; import com.travel.term.service.RoleService; import com.travel.term.service.UserService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; /** * (User)表服务实现类 * * @author cai * @since 2023-12-13 */ @Service public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService { @Resource private UserService userService; @Override public Boolean deleteById(Long id) { // 创建一个集合存放id List<Long> ids = new ArrayList<>(); ids.add(id); // 查询是否能被删除 return this.couldDelete(ids) ? this.removeById(id) : false; } /** * 分页查询业务实现 * * @param reqRole * @return */ @Override public List<Role> list(ReqRole reqRole) { LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(!StringUtils.nullOrEmpty(reqRole.getName()), Role::getName, reqRole.getName()); // 模糊查询名字 List<Role> list = this.list(queryWrapper); // 将permissionsIds转化为名字 list.stream().peek(item -> { if (item.getPermissionIds() != null && item.getPermissionIds() != "") { //转为list集合 List<String> split = Arrays.asList(item.getPermissionIds().split(",")); // 查询权限名字组 List<String> names = this.getBaseMapper().queryIds(split); item.setPermissionName(names.toString()); System.out.println(split); } }).collect(Collectors.toList()); //若有权限条件查询则进行查询 if (StringUtils.nullOrEmpty(reqRole.getPermissionIds())) { return list; } List<String> ids = Arrays.asList(reqRole.getPermissionIds().split(",")); // 对权限查询进行模糊处理 return list.stream().map(item -> { if (StringUtils.nullOrEmpty(item.getPermissionIds())) { return null; } String[] split = item.getPermissionIds().split(","); List<String> idList = Arrays.asList(split); // 查询是否包含要的id return idList.containsAll(ids) ? item : null; }).collect(Collectors.toList()); } /** * 查询role是否被引用 * * @param ids * @return */ private Boolean couldDelete(List<Long> ids) { LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(ids.size() != 0, User::getRoleId, ids); // 查询要删除的roleId是否被user引用,确保数据库外键约束不被破坏 List<User> list = userService.list(queryWrapper); return list.size() == 0; } }
UserServiceImpl
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.travel.term.common.constant.RoleConstant; import com.travel.term.common.data.resultAndReq.PageResult; import com.travel.term.common.data.resultAndReq.Result; import com.travel.term.common.utils.EncryptUtils; import com.travel.term.common.utils.StringUtils; import com.travel.term.entity.Role; import com.travel.term.entity.req.ReqUser; import com.travel.term.entity.req.ReqLoginUser; import com.travel.term.mapper.UserMapper; import com.travel.term.entity.User; import com.travel.term.service.UserService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.HashMap; import java.util.List; import java.util.stream.Collectors; /** * (User)表服务实现类 * * @author cai * @since 2023-12-04 22:02:03 */ @Service @Slf4j public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { @Override public User checkUserInfo(ReqLoginUser loginUserVo) { log.info(loginUserVo.toString()); // 检查账号是否存在 User user = this.baseMapper.checkAccount(loginUserVo.getAccount()); if (StringUtils.nullOrEmpty(user)) { // 没有该账号 return new User().setId("-1"); } if (user.getStatus() == 0) { return user; } // 检查密码是否正确 // 对密码进行解密 String password = EncryptUtils.decrypt(user.getPassword()); if (!StringUtils.nullOrEmpty(loginUserVo.getPassword()) && password.equals(loginUserVo.getPassword())) { return user; } return null; } @Override public Result<Boolean> register(User user) { String password = EncryptUtils.kaisaEncrypt(user.getPassword()); user.setPassword(password); user.setRoleId(RoleConstant.用户); boolean save = this.save(user); return save == true ? Result.success("注册成功") : Result.fail("注册失败"); } @Override public PageResult<User> list(ReqUser reqUser) { LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(!StringUtils.nullOrEmpty(reqUser.getAccount()), User::getAccount, reqUser.getAccount()) .eq(!StringUtils.nullOrEmpty(reqUser.getPhone()), User::getPhone, reqUser.getPhone()) .eq(!StringUtils.nullOrEmpty(reqUser.getEmail()), User::getEmail, reqUser.getEmail()) .eq(!StringUtils.nullOrEmpty(reqUser.getGender()), User::getGender, reqUser.getGender()) .eq(!StringUtils.nullOrEmpty(reqUser.getRoleId()), User::getRoleId, reqUser.getRoleId()) .eq(!StringUtils.nullOrEmpty(reqUser.getStatus()), User::getStatus, reqUser.getStatus()); //查询 List<User> list = this.list(queryWrapper); // 把全部role查出来减少数据库访问操作 HashMap<String, String> newRoleMap = (HashMap<String, String>) this.baseMapper.roleList().stream().collect(Collectors.toMap(Role::getId, Role::getName)); //roleId映射名字 list.stream().peek(item -> { // 访问数据库获取名字 if (StringUtils.nullOrEmpty(item.getRoleId()) || StringUtils.nullOrEmpty(newRoleMap.get(item.getRoleId().toString()))) { System.out.println(item.getRoleId() + " " + newRoleMap.get(item.getRoleId().toString())); item.setRoleName(""); } else { item.setRoleName(newRoleMap.get(item.getRoleId().toString())); } }).collect(Collectors.toList()); return new PageResult<>(list); } @Override public Result<Boolean> checkInfo(String checkColumn) { return StringUtils.nullOrEmpty(this.baseMapper.checkAccount(checkColumn)) ? Result.success("不重复") : Result.fail("已存在,不允许重复"); } }
TravelSystemApplication
启动类,相当于入口
import lombok.extern.slf4j.Slf4j; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.travel.term.mapper.*") @Slf4j public class TravelSystemApplication { public static void main(String[] args) { SpringApplication.run(TravelSystemApplication.class, args); log.info("http://localhost:8848/swagger-ui/index.html"); } }
resource
mapper
IFileMapper.xml
<?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="com.travel.term.mapper.IFileMapper"> </mapper>
PermissionMapper.xml
<?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="com.travel.term.mapper.PermissionMapper"> </mapper>
RoleMapper.xml
<?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="com.travel.term.mapper.RoleMapper"> <select id="queryIds" resultType="java.lang.String"> select description from permission <where> id in <foreach collection="permissionIds" open="(" close=")" item="id" separator=","> #{id} </foreach> </where> </select> </mapper>
UserMapper.xml
<?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="com.travel.term.mapper.UserMapper"> <resultMap type="com.travel.term.entity.User" id="UserMap"> <result property="id" column="id" jdbcType="VARCHAR"/> <result property="account" column="account" jdbcType="VARCHAR"/> <result property="phone" column="phone" jdbcType="VARCHAR"/> <result property="email" column="email" jdbcType="VARCHAR"/> <result property="password" column="password" jdbcType="VARCHAR"/> <result property="gender" column="gender" jdbcType="INTEGER"/> <result property="age" column="age" jdbcType="INTEGER"/> <result property="birth" column="birth" jdbcType="TIMESTAMP"/> <result property="roleId" column="role_id" jdbcType="INTEGER"/> </resultMap> <!-- 批量插入 --> <insert id="insertBatch" keyProperty="id" useGeneratedKeys="true"> insert into travel.user(account, phone, email, password, gender, age, birth, role_id) values <foreach collection="entities" item="entity" separator=","> (#{entity.account}, #{entity.phone}, #{entity.email}, #{entity.password}, #{entity.gender}, #{entity.age}, #{entity.birth}, #{entity.roleId}) </foreach> </insert> <!-- 批量插入或按主键更新 --> <insert id="insertOrUpdateBatch" keyProperty="id" useGeneratedKeys="true"> insert into travel.user(account, phone, email, password, gender, age, birth, role_id) values <foreach collection="entities" item="entity" separator=","> (#{entity.account}, #{entity.phone}, #{entity.email}, #{entity.password}, #{entity.gender}, #{entity.age}, #{entity.birth}, #{entity.roleId}) </foreach> on duplicate key update account = values(account) , phone = values(phone) , email = values(email) , password = values(password) , gender = values(gender) , age = values(age) , birth = values(birth) , role_id = values(role_id) </insert> <select id="checkAccount" parameterType="String" resultType="com.travel.term.entity.User"> select * from user u <where> u.account = #{account} or u.phone = #{account} or u.email = #{account} </where>; </select> </mapper>
templates(动态模版文件)
application.yaml(配置文件)
部署
打包
maven打包,可直接使用idea的maven插件
在traget下有个打包完的jar包
部署
将jar包在服务器上启动
使用命令如下:
#后台启动 nohup java -jar -Xms128m -Xmx256m travel-system-0.0.1-SNAPSHOT.jar >/dev/null 2>&1 &
通过指令查看是否运行成功
ps -ef | grep travel-system-0.0.1-SNAPSHOT.jar