Spring Boot图书管理系统项目实战-2.项目搭建
导航:
pre: 1.系统功能和架构介绍
next:3.用户登录
只挑重点的讲,具体的请看项目源码。
1.项目源码:
需要源码的朋友,请捐赠任意金额后留下邮箱发送:)
2.添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--spring security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--thymeleaf-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--SpringBoot热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
<!--JDBC-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--commons-lang3-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<!-- fonts file cannot use filter as the data structure of byte file will be changed via filter -->
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>static/layui/font/**</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
3.配置文件application.yml
server:
port: 8080
servlet:
context-path:
session:
timeout: 7200s
spring:
mvc:
static-path-pattern: /**
date-format: yyyy-MM-dd
favicon:
enabled: true
thymeleaf:
encoding: UTF-8
cache: false
mode: HTML
prefix: classpath:/templates/
suffix: .html
# 数据源
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root123
url: jdbc:mysql://localhost:3306/bookman?characterEncoding=utf-8&useSSL=false
type: com.zaxxer.hikari.HikariDataSource
hikari:
pool-name: BookHikariPool
maximum-pool-size: 12
connection-timeout: 60000
connection-test-query: SELECT 1
servlet:
multipart:
max-request-size: 100MB
max-file-size: 50MB
# mybatis
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml
configuration:
map-underscore-to-camel-case: true
# 文件上传路径
web:
upload:
path: D:/upload/
4.导入数据库
数据库脚本在:src/resources/bookman.sql
创建数据库:bookman 编码:UTF-8
执行SQL语句
5.工具类
5.1 文件上传
public class UploadUtils {
public static String upload(MultipartFile file, String path, String fileName) throws Exception {
// 生成新的文件名
String realPath = path + "/" + UUID.randomUUID().toString().replace("-", "") + fileName.substring(fileName.lastIndexOf("."));
File dest = new File(realPath);
// 判断文件父目录是否存在
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdir();
}
// 保存文件
file.transferTo(dest);
return dest.getName();
}
}
5.2 MD5
/**
* md5工具类
*/
public class MD5Util {
public static final int time = 5;
public static final String SALT = "springsecurity";
/**
* 密码加密方法
*
* @param password
* @return
*/
public static String encode(String password) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
}
try {
for (int i = 0; i < time; i++) {
byte[] bytes = digest.digest((password + SALT).getBytes("UTF-8"));
password = String.format("%032x", new BigInteger(1, bytes));
}
return password;
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
public static void main(String[] args) {
System.out.println(MD5Util.encode("admin"));
}
}
5.3 spring security
/**
* @Description: spring security工具类
* @Author laoxu
* @Date 2019/5/11 17:20
**/
public class SecurityUtil {
public static String getLoginUser(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (!(authentication instanceof AnonymousAuthenticationToken)) {
String currentUserName = authentication.getName();
return currentUserName;
}
return "";
}
}
6.配置类
6.1 MVC配置
/** mvc配置,例如:资源映射、视图解析、拦截器等
* @author laoxu
* @create 2018-10-23
**/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
SessionTimeoutInterceptor sessionTimeoutInterceptor;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("/assets/ckeditor/**").
addResourceLocations("classpath:/static/assets/ckeditor/").
setCachePeriod(2592000);
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index").setViewName("index");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/success").setViewName("success");
registry.addViewController("/admin").setViewName("admin");
registry.addViewController("/book").setViewName("book");
registry.addViewController("/bookAdd").setViewName("bookAdd");
registry.addViewController("/bookEdit").setViewName("bookEdit");
registry.addViewController("/bookBorrow").setViewName("bookBorrow");
registry.addViewController("/bookBorrowAdd").setViewName("bookBorrowAdd");
registry.addViewController("/bookBorrowEdit").setViewName("bookBorrowEdit");
registry.addViewController("/bookReBorrow").setViewName("bookReBorrow");
registry.addViewController("/bookReBorrowEdit").setViewName("bookReBorrowEdit");
registry.addViewController("/bookReturn").setViewName("bookReturn");
registry.addViewController("/bookCategory").setViewName("bookCategory");
registry.addViewController("/bookLanguage").setViewName("bookLanguage");
registry.addViewController("/bookPublisher").setViewName("bookPublisher");
registry.addViewController("/bookShelf").setViewName("bookShelf");
registry.addViewController("/bookReader").setViewName("bookReader");
registry.addViewController("/bookStat").setViewName("bookStat");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(sessionTimeoutInterceptor).addPathPatterns("/**").
excludePathPatterns("/api/book/list","/bookDetail/*","/","/index","/login","/static/**","/logout");
}
}
6.2 统一返回结构
/**
* 请求返回结果
*
* @author laoxu
* @create 2018-10-23
**/
public class Result<T> {
private boolean success = true;
private int code = ErrorStatus.OK.getCode();
private String message = "";
private T data;
public static <T> Result<T> newInstance() {
return new Result<T>();
}
public Result() {
}
public Result(T data) {
this.data = data;
}
public Result(ErrorStatus status) {
this.message = status.getMessage();
this.code = status.getCode();
}
public Result(String message) {
this.message = message;
}
public Result(int code, String message) {
this.message = message;
this.code = code;
}
public Result(int code, String message, T data) {
this.message = message;
this.code = code;
this.data = data;
}
public Result<T> status(ErrorStatus status) {
this.message = message;
this.code = code;
return this;
}
public Result<T> ok() {
success = true;
return this;
}
public Result<T> fail() {
success = false;
return this;
}
public Result<T> message(String message) {
this.message = message;
return this;
}
public Result<T> data(T data) {
this.data = data;
return this;
}
public Result<T> code(int code) {
this.code = code;
return this;
}
public boolean isSuccess() {
return success;
}
// 省略get,set
}
/**
* @Description: 响应消息体
* @Author laoxu
* @Date 2019/12/21 9:50
**/
public class ResultBean<T> {
/**响应编码*/
private int code;
/**响应消息*/
private String msg;
/**数据总量*/
private int count;
/**数据*/
private T data;
public ResultBean() {
}
public ResultBean(int code, String msg, int count, T data) {
super();
this.code = code;
this.msg = msg;
this.count = count;
this.data = data;
}
@Override
public String toString() {
return "R [code=" + code + ", msg=" + msg + ", count=" + count + ", data=" + data + "]";
}
// 省略get,set
}
/**
* 返回结果工具类
*
* @author laoxu
* @create 2018-10-23
**/
public class ResultUtil {
public static boolean isOk(Result<?> result){
return null != result && result.getCode() == ErrorStatus.OK.getCode();
}
public static <T> Result<T> ok(){
return new Result<T>(ErrorStatus.OK);
}
public static <T> Result<T> ok(T data){
return new Result<T>(ErrorStatus.OK.getCode(), ErrorStatus.OK.getMessage(), data);
}
public static <T> Result<T> fail(){
return new Result<T>(ErrorStatus.BAD_REQUEST).fail();
}
public static <T> Result<T> status(ErrorStatus status){
return new Result<T>(status.getCode(), status.getMessage()).fail();
}
public static <T> Result<T> fail(ErrorStatus status){
return new Result<T>(status.getCode(), status.getMessage()).fail();
}
public static <T> Result<T> fail(String message){
return fail(ErrorStatus.BAD_REQUEST.getCode(), message, (T)null).fail();
}
public static <T> Result<T> fail(int code, String message){
return new Result<T>(code, message).fail();
}
public static <T> Result<T> fail(int code ,String message, T data){
return new Result<T>(code, message, data).fail();
}
public static <T> Result<T> notfound(){
return new Result<T>(ErrorStatus.NOT_FOUND).fail();
}
}
6.3 错误信息封装
/**
* 错误代号和信息
*
* @author laoxu
* @create 2018-10-23
**/
public enum ErrorStatus {
OK(200, "OK"),
FOUND(302, "Found"),
BAD_REQUEST(400, "Bad Request"),
UNAUTHORIZED(401, "Unauthorized"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error"),
SERVICE_UNAVAILABLE(503, "Service Unavailable");
private final int code;
private final String message;
ErrorStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
6.4 自定义异常
/**
* @Description: 异常处理器
* @Author laoxu
* @Date 2019/7/3 22:14
**/
@ControllerAdvice
public class ExceptionsHandler {
@ResponseBody
@ExceptionHandler(UnAuthorizedException.class)//可以直接写@ExceptionHandler,不指明异常类,会自动映射
public Result<String> customGenericExceptionHnadler(UnAuthorizedException exception){ //还可以声明接收其他任意参数
return ResultUtil.fail(Integer.valueOf(exception.getErrorCode()),exception.getErrorMessage());
}
}
7.静态资源
添加 layui文件
Spring Boot图书管理系统项目实战-2.项目搭建的更多相关文章
- 图书-技术-SpringBoot:《Spring Boot 企业级应用开发实战》
ylbtech-图书-技术-SpringBoot:<Spring Boot 企业级应用开发实战> Spring Boot 企业级应用开发实战,全书围绕如何整合以 Spring Boot 为 ...
- 《Spring Boot 入门及前后端分离项目实践》系列介绍
课程计划 课程地址点这里 本课程是一个 Spring Boot 技术栈的实战类课程,课程共分为 3 个部分,前面两个部分为基础环境准备和相关概念介绍,第三个部分是 Spring Boot 项目实践开发 ...
- Vue+Spring Boot 前后端分离的商城项目开源啦!
新蜂商城 Vue 移动端版本开源啦! 去年开源新蜂商城项目后,就一直在计划这个项目 Vue 版本的改造,2020 年开始开发并且自己私下一直在测试,之前也有文章介绍过测试过程和存在的问题,修改完成后, ...
- Spring Boot会员管理系统——处理文件上传
温馨提示 Spring Boot会员管理系统的中,需要涉及到Spring框架,SpringMVC框架,Hibernate框架,thymeleaf模板引擎.所以,可以学习下这些知识.当然,直接入门的话使 ...
- Spring Boot 从入门到实战汇总
之前写过几篇spring boot入门到实战的博文,因为某些原因没能继续. 框架更新迭代很快,之前还是基于1.x,现在2.x都出来很久了.还是希望能从基于该框架项目开发的整体有一个比较系统的梳理,于是 ...
- spring boot / cloud (十八) 使用docker快速搭建本地环境
spring boot / cloud (十八) 使用docker快速搭建本地环境 在平时的开发中工作中,环境的搭建其实一直都是一个很麻烦的事情 特别是现在,系统越来越复杂,所需要连接的一些中间件也越 ...
- Spring Boot从入门到实战:整合Web项目常用功能
在Web应用开发过程中,一般都涵盖一些常用功能的实现,如数据库访问.异常处理.消息队列.缓存服务.OSS服务,以及接口日志配置,接口文档生成等.如果每个项目都来一套,则既费力又难以维护.可以通过Spr ...
- 用Spring Boot零配置快速创建web项目(1)
一.Spring Boot简介 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人 ...
- Spring boot入门(一):快速搭建Spring boot项目
(一)Spring boot介绍 本部分摘自:https://www.zhihu.com/question/64671972/answer/223383505 Spring Boot是由Pivotal ...
- 《Spring Boot 入门及前后端分离项目实践》目录
开篇词:SpringBoot入门及前后端分离项目实践导读 第02课:快速认识 Spring Boot 技术栈 第03课:开发环境搭建 第04课:快速构建 Spring Boot 应用 第05课:Spr ...
随机推荐
- Kafka 社区KIP-382中文译文(MirrorMaker2/集群复制/高可用/灾难恢复)
译者:对于Kafka高可用的课题,我想每个公司都有自己的方案及思考,这是一个仁者见仁智者见智的命题,而社区给出了一个较大的特性,即MirrorMaker 2.0,不论是准备做高可用还是单纯的数据备份, ...
- 达梦数据库varchar和nvarchar的验证
达梦数据库varchar和nvarchar的验证 测试SQL create tablespace zhaobsh datafile '/opt/dmdbms/data/DAMENG/zhaobsh.d ...
- [转帖]HTTP与HTTPS超文本传输协议的区别是什么
https://www.likecs.com/show-308649882.html 随着越来越多的网站使用HTTPS加密,现在HTTPS的使用已经成了硬性要求了.虽然说https是http的安全版, ...
- vm-storage在全部都是新metric情况下的写入性能测试
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 vm-storage中,写入索引的性能要比写入data p ...
- 在Protocol Buffers中导入当前目录中的.proto文件
在protobuf中导入当前目录中的.proto文件时,可以使用相对路径.相对路径是相对于当前.proto文件所在的目录来引用其他.proto文件. 假设有以下目录结构: my_project/ |- ...
- TienChin-课程管理-添加课程接口
CourseController.java @PreAuthorize("hasPermission('tienchin:course:create')") @Log(title ...
- go中string是如何实现的呢
go中string是如何实现的呢 前言 实现 go语言中的string是不可变的 []byte转string string转[]byte 字符串的拼接 +方式进行拼接 fmt 拼接 Join 拼接 b ...
- 文字溢出hover展示
我这个后端返回的是html结构,不然不用加v-html,需要依赖element Ui 的文字提示 <el-tooltip placement="top"> <p ...
- 精进语言模型:探索LLM Training微调与奖励模型技术的新途径
精进语言模型:探索LLM Training微调与奖励模型技术的新途径 LLMs Trainer 是一个旨在帮助人们从零开始训练大模型的仓库,该仓库最早参考自 Open-Llama,并在其基础上进行扩充 ...
- 关于飞桨UIE等模型预测推理时间很久的问题分析以及解决,蒸馏剪枝部署问题解决
1.关于飞桨UIE等模型预测推理时间很久的问题分析以及解决 1.1.原因分析 用uie做实体识别,Taskflow预测的时间与schema内的实体类别数量成正比,schema里面有多少个实体类别 实体 ...