项目工程结构
项目采用普通的SpringBoot项目结构,其中common模块下是全局异常处理和统一返回结果。server模块则是整个项目的业务代码。
easypan ├── common │ ├── common-util │ └── pom.xml ├── learning-online-content └── server
|
根据项目结构创建出父工程easypan
,删除其中的src
目录,并两个子模块common
和server
版本控制
在父工程easypan
的pom文件中添加版本依赖信息
pom.xml<?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.6.1</version> <relativePath/> </parent> <groupId>com.swx</groupId> <artifactId>easypan</artifactId> <version>1</version> <packaging>pom</packaging> <name>easypan</name> <description>easypan</description> <modules> <module>common</module> <module>server</module> </modules>
<properties> <springboot.version>2.6.1</springboot.version> <logback.version>1.2.10</logback.version> <mysql.version>8.0.30</mysql.version> <mybatis-plus.version>3.4.1</mybatis-plus.version> <aspectjweaver.version>1.9.4</aspectjweaver.version> <fastjson.version>2.0.21</fastjson.version> <commons.lang3.version>3.4</commons.lang3.version> <commons.codec.version>1.9</commons.codec.version> <commons.io.version>2.5</commons.io.version> <ws.schild.version>3.3.1</ws.schild.version> </properties>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> <version>${springboot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>${springboot.version}</version> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency>
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback.version}</version> </dependency>
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectjweaver.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons.lang3.version}</version> </dependency>
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>${commons.codec.version}</version> </dependency>
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>${commons.io.version}</version> </dependency> <dependency> <groupId>ws.schild</groupId> <artifactId>jave-all-deps</artifactId> <version>${ws.schild.version}</version> </dependency> </dependencies> </dependencyManagement>
<build> <finalName>${project.name}</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
|
统一返回结果
通过拦截Controller的返回结果和全局异常,将其封装成统一的格式,并使用RestController返回JSON形式的数据给前端。
{ "code":20000, "message":"成功", "data":{ "info":"测试成功" } }
|
项目介绍地址:
SpringBoot统一封装返回结果和异常情况
将GitHub代码下载到本地,将其中的common-util
放到common
模块下,作为其子模块。
业务代码工程
引入依赖
在server
模块的pom文件中添加依赖信息
pom.xml<dependencies> <dependency> <groupId>com.swx</groupId> <artifactId>common-util</artifactId> <version>1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </exclusion> <exclusion> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </exclusion> </exclusions> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency>
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency>
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> </dependency>
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency>
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency>
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity</artifactId> <version>1.7</version> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>ws.schild</groupId> <artifactId>jave-all-deps</artifactId> </dependency> </dependencies>
|
启动类
创建 EasyPanApplication
EasyPanApplication@EnableAsync @EnableScheduling @EnableTransactionManagement public class EasyPanApplication { public static void main(String[] args) { SpringApplication.run(EasyPanApplication.class, args); } }
|
配置文件
创建application.properties
配置文件
server.port=7090 server.servlet.context-path=/api
server.servlet.session.timeout=PT60M
spring.mvc.favicon.enable=false
spring.mvc.throw-exception-if-no-handler-found=true spring.web.resources.add-mappings=false spring.servlet.multipart.max-file-size=15MB spring.servlet.multipart.max-request-size=15MB
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/easypan?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true spring.datasource.username=root spring.datasource.password=swx852345 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.hikari.pool-name=HikariCPDatasource spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.idle-timeout=180000 spring.datasource.hikari.maximum-pool-size=10 spring.datasource.hikari.auto-commit=true spring.datasource.hikari.max-lifetime=1800000 spring.datasource.hikari.connection-timeout=30000 spring.datasource.hikari.connection-test-query=SELECT 1
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl mybatis-plus.global-config.db-config.logic-delete-value=1 mybatis-plus.global-config.db-config.logic-not-delete-value=0 mybatis-plus.mapper-locations=classpath:mapper/*.xml
spring.mail.host=smtp.qq.com
spring.mail.port=465
spring.mail.username=2627311935@qq.com
spring.mail.password=tykyolipdlapdifi
spring.mail.default-encoding=UTF-8
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.debug=true
spring.redis.database=0 spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=swx852345
spring.redis.jedis.pool.max-active=20
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout=2000
project.folder=/Users/swcode/Documents/webser/web_app/easypan
log.root.level=info
admin.emails=test@qq.com
dev=false
qq.app.id=12333 qq.app.key=2222222 qq.url.authorization=https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=%s&redirect_uri=%s&state=%s qq.url.access.token=https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s qq.url.openid=https://graph.qq.com/oauth2.0/me?access_token=%S qq.url.user.info=https://graph.qq.com/user/get_user_info?access_token=%s&oauth_consumer_key=%s&openid=%s qq.url.redirect=http://easypan.wuhancoder.com/qqlogincalback
|
日志文件,logback-spring.xml
logback-spring.xml<?xml version="1.0" encoding="UTF-8" ?> <configuration scan="true" scanPeriod="10 minutes"> <appender name="stdot" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss,GMT+8} [%p][%c][%M][%L]-> %m%n</pattern> </layout> </appender>
<springProperty scope="context" name="log.path" source="project.folder"/> <springProperty scope="context" name="log.root.level" source="log.root.level"/>
<property name="LOG_FOLDER" value="logs"/> <property name="LOG_FILE_NAME" value="easypan.log"/>
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}/${LOG_FOLDER}/${LOG_FILE_NAME}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${log.path}/${LOG_FOLDER}/${LOG_FILE_NAME}.%d{yyyyMMdd}.%i</FileNamePattern> <cleanHistoryOnStart>true</cleanHistoryOnStart> <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <MaxFileSize>20MB</MaxFileSize> </TimeBasedFileNamingAndTriggeringPolicy> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <charset>utf-8</charset> <pattern>%d{yyyy-MM-dd HH:mm:ss,GMT+8} [%p][%c][%M][%L]-> %m%n</pattern> </encoder> <append>false</append> <prudent>false</prudent> </appender>
<root level="${log.root.level}"> <appender-ref ref="stdot"/> <appender-ref ref="file"/> </root>
</configuration>
|
配置类
创建com.swx.easypan.config
包。
Mybatis Plus
在com.swx.easypan.config
包下创建Mybatis Plus的配置文件
MybatisPlusConfig@MapperScan(basePackages = {"com.swx.easypan.mapper"}) @EnableTransactionManagement @Configuration public class MybatisPlusConfig {
@Bean public MetaObjectHandler metaObjectHandler() { return new MyMetaObjectHandler(); }
@Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }
|
自动填充
MyMetaObjectHandlerpublic class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { boolean createTime = metaObject.hasSetter("createTime"); boolean updateTime = metaObject.hasSetter("updateTime"); if (updateTime) { strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } if (createTime) { strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); } }
@Override public void updateFill(MetaObject metaObject) { boolean updateTime = metaObject.hasSetter("updateTime"); if (updateTime) { strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); } } }
|
配置文件变量类
AppConfig@Component("appConfig") public class AppConfig {
@Value("${spring.mail.username}") private String sendUsername;
@Value("${admin.emails}") private String emails;
@Value("${project.folder}") private String projectFolder;
public String getSendUsername() { return sendUsername; }
public String getEmails() { return emails; } public String getProjectFolder() { return projectFolder; } }
|
代码生成
在测试目录中创建代码生成器,运行后会在server模块中创建Mybatis Plus的基础代码
CodeGeneratorpublic class CodeGenerator {
public static void main(String[] args) { AutoGenerator mpg = new AutoGenerator();
GlobalConfig gc = new GlobalConfig(); String projectPath = System.getProperty("user.dir"); gc.setOutputDir(projectPath + "/server/src/main/java"); gc.setAuthor("sw-code"); gc.setOpen(false); gc.setFileOverride(false); gc.setServiceName("%sService"); gc.setIdType(IdType.AUTO); mpg.setGlobalConfig(gc);
DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql:///easypan?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8&nullCatalogMeansCurrent=true"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("swx852345"); mpg.setDataSource(dsc);
PackageConfig pc = new PackageConfig(); pc.setParent("com.swx.easypan"); pc.setEntity("pojo"); pc.setMapper("mapper"); pc.setService("service"); pc.setController("controller"); mpg.setPackageInfo(pc);
StrategyConfig strategy = new StrategyConfig(); strategy.setInclude("file_share", "file_info", "user_info", "email_code"); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); strategy.setEntityLombokModel(true); strategy.setLogicDeleteFieldName("deleted"); TableFill createTime = new TableFill("create_time", FieldFill.INSERT); TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE); List<TableFill> tableFills = new ArrayList<>(); tableFills.add(createTime); tableFills.add(updateTime); strategy.setTableFillList(tableFills); strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true); strategy.setControllerMappingHyphenStyle(true); mpg.setStrategy(strategy);
mpg.execute(); } }
|
工具类
创建包 com.swx.easypan.utils
,以下工具方法都放在该包下
StringToolspublic class StringTools {
public static String getRandomNumber(Integer count) { return RandomStringUtils.random(count, false, true); }
public static String getRandomString(Integer count) { return RandomStringUtils.random(count, true, true); }
public static String rename(String filename) { return getFilename(filename) + "_" + getRandomString(Constants.LENGTH_5) + getFileSuffix(filename); }
public static String getFilename(String filename) { int index = filename.lastIndexOf("."); if (index == -1) { return filename; } return filename.substring(0, index); }
public static String getFileSuffix(String filename) { int index = filename.lastIndexOf("."); if (index == -1) { return ""; } return filename.substring(index); } }
|
FileUtils
FileUtilspublic class FileUtils {
public static void writeImage(HttpServletResponse response, String filePath) { if (!StringUtils.hasText(filePath)) { return; } String imageSuffix = StringTools.getFileSuffix(filePath); imageSuffix = imageSuffix.replace(".", ""); String contentType = "image/" + imageSuffix; response.setContentType(contentType); response.setHeader("Cache-Control", "max-age=2592000"); FileUtil.readFile(response, filePath); }
public static void writeDownloadFile(HttpServletResponse response, HttpServletRequest request, String filename, String filePath) throws UnsupportedEncodingException { response.setContentType("application/x-msdownload; character=UTF-8"); if (request.getHeader("User-Agent").toLowerCase().indexOf("msie") > 0) { filename = URLEncoder.encode(filename, "UTF-8"); } else { filename = new String(filename.getBytes("UTF-8"), "ISO8859-1"); } response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\""); FileUtil.readFile(response, filePath); } }
|