目录
一、案例说明
二、数据库
三、案例源码
3.1、pom文件
3.2、Application.yml
3.3、项目结构
a)整体结构
b)Java代码部分
c)资源文件部分
3.4、业务功能的实现
1)配置类
2)实体类
3)Mapper文件
4)Service
5)Controller
6)视图
四、测试效果图
启动项目
浏览器访问
添加功能
修改
删除
附件:pom文件
Idea 2022.3.3汉化版 、mysql 5.7 、 JDK 8
springboot + thymeleaf + restful + layui.css + bootstrap
图书表和出版社表为例,实现增删改查的功能。
该案例需要准备一些样式表:
layui官网
bootstrap的下载地址
bootstrap-select下载地址
bootstrap-table下载地址
(在bootstrap-select和bootstrap-table中也都是使用文件中dist目录下的文件)
commons-lang3的官方教程
commons-lang3的官方API
1. commons-lang3是Apache提供的一个java.lang包的增强版本,Lang3为java.lang API提供了许多帮助程序实用程序,特别是字符串操作方法,基本数值方法,对象反射,并发,创建和序列化以及系统属性。此外,它还包含对java.urti.Date的基本增强,以及一系列专用于构建方法的实用程序,例如hashCode,toString和equals。
2.提供了官方的API地址,可通过文档获取需要的支持。
Book表
Publish表
温馨小贴士:book 表中字段 pic 为图片路径(表中是图片名字和格式)。
在案例中使用到了文件(图片)上传。则需要注意的是:文件保存位置。
//将所有/upimg/的访问请求都拦截到指定目录
registry.addResourceHandler("/upimg/**").addResourceLocations("file:D://uploadImg//");
由于在配置类BeanConfig中配置了拦截器(),将所有/upimg/的访问请求都拦截到指定目录。
所以,需要根据指定目录存放文件(图片)。
本案例文件(图片)存放地址为:
没有文件夹的要根据自己的设置进行创建,并存放使用的图片。否则,项目运行无法加载图片。
1、需要加载各种所需依赖坐标。
2、构建资源。
target文件夹是项目编译之后的资源文件夹。该文件夹中存在的内容才可以被项目中读取使用。
如果target中没有所需要的文件资源时, 检查pom.xml文件中是否拥有以下配置:
src/main/java
**/*.yml
**/*.properties
**/*.xml
false
src/main/resources
**/*.css
**/*.js
**/*.html
**/*.png
**/*.jpg
**/*.properties
**/*.yml
**/*.xml
**/*.conf
false
# 服务器设置: 端口号和访问路径
server:
port: 8088
servlet:
context-path: /shq
# 数据源设置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/2101_files?serverTimezone=UTC
username: root
password: 123456
thymeleaf:
cache: false
suffix: .html
web:
resources:
static-locations: classpath:/templates/,classpath:/static/image/
# 让控制台显示执行的SQL语句
logging:
level:
cn:
shq:
mapper: debug
# mybatis配置
mybatis:
type-aliases-package: cn.shq.model # 别名
configuration:
auto-mapping-behavior: full #设置全自动映射
use-column-label: true # 列标签代替字段名
#设置mapper的路径
mapper-locations: classpath:cn/shq/mapper/*.xml
案例中所使用的CSS、JS文件需要从各个官网上下载(本文头部提供的有各个网址)。
把静态文件放到static下面;把HTML文件放到templates下面;
BeasConfig.java
package cn.shq.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ResourceUtils;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class BeanConfig extends WebMvcConfigurationSupport {
/**
* 拦截器
* */
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
// 自定义设置:指定程序中 路径为 /upimg/** 的文件,统统都到指定的Locations中去找(即 D://uploadImg//目录下去找)
registry.addResourceHandler("/upimg/**").addResourceLocations("file:D://uploadImg//");
// 访问路径为/static/的请求,都到项目中static目录中。
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
// 在pom文件中 加载的各种前端文件 保存在resources/webjar目录下。
// 如果没有这一行代码的配置,则运行测试发现:没有样式表,找不到对应的样式文件。
registry.addResourceHandler("/webjars/**").addResourceLocations(ResourceUtils.CLASSPATH_URL_PREFIX +"/META-INF/resources/webjars/");
super.addResourceHandlers(registry);
}
/**
* 添加restful支持
*/
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
hiddenHttpMethodFilter.setBeanName("HiddenHttpMethodFilter");
hiddenHttpMethodFilter.setMethodParam("_method");
return hiddenHttpMethodFilter;
}
}
Book.java
package cn.shq.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
private long bookId;
private String bookName;
private String author;
private long price;
private long pubId;
/**
* @DateTimeFormat:可以解决日期格式问题。
* 因为页面传递过来的是String类型,而java中需要是Date类型。所以使用该注解可以进行类型转换。
* 也可以使用另外一种方式实现类型转换:自己写一个日期格式转换类。
* */
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date pubDate;
private String pic;
}
Publish.java
package cn.shq.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Publish {
private long pubId;
private String pubName;
private String loc;
}
BookVO.java
package cn.shq.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookVO {
// book类中的属性
private long bookId;
private String bookName;
private String author;
private long price;
private Date pubDate;
private String pic;
// publish 出版社
private Publish publish;
}
BookMapper.java
package cn.shq.mapper;
import cn.shq.model.Book;
import cn.shq.model.BookVO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;
import java.util.List;
@Mapper
@Component
public interface BookMapper {
// 查询全部
List selectAll();
// 添加
int insert(Book book);
// 删除 (根据编号进行删除)
int del(Integer bookId);
// 修改
int update(Book book);
// 条件查询 -----> 根据编号查找对应信息
Book findByID(Integer bookId);
}
BookMapper.xml
insert into book(bookName,pubId,pubDate,pic)values(#{bookName},#{pubId,jdbcType=INTEGER},#{pubDate,jdbcType=TIMESTAMP},#{pic})
delete from book where bookId = #{bookId}
update book set bookName= #{bookName},pubId = #{pubId},pubDate = #{pubDate},pic = #{pic}
where bookId = #{bookId}
PublishMapper.java
package cn.shq.mapper;
import cn.shq.model.Publish;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;
import java.util.List;
@Mapper
@Component
public interface PublishMapper {
@Select("select * from publish")
List selectAll();
}
BookService.java
package cn.shq.service;
import cn.shq.model.Book;
import cn.shq.model.BookVO;
import java.util.List;
public interface BookService {
// 查询全部
List selectAll();
// 添加
int insert(Book book);
// 删除 (根据编号进行删除)
int del(Integer bookId);
// 修改
int update(Book book);
// 条件查询 -----> 根据编号查找对应信息
Book findByID(Integer bookId);
}
BookServiceImpl.java
package cn.shq.service.impl;
import cn.shq.mapper.BookMapper;
import cn.shq.model.Book;
import cn.shq.model.BookVO;
import cn.shq.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class BookServiceImp implements BookService {
@Autowired
BookMapper bookMapper;
@Override
public List selectAll() {
return bookMapper.selectAll();
}
@Override
public int insert(Book book) {
return bookMapper.insert(book);
}
@Override
public int del(Integer bookId) {
return bookMapper.del(bookId);
}
@Override
public int update(Book book) {
return bookMapper.update(book);
}
@Override
public Book findByID(Integer bookId) {
return bookMapper.findByID(bookId);
}
}
PublicServiceImpl.java
package cn.shq.service.impl;
import cn.shq.mapper.PublishMapper;
import cn.shq.model.Publish;
import cn.shq.service.PublishService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional
public class PublishServiceImpl implements PublishService {
@Autowired
PublishMapper mapper;
@Override
public List selectAll() {
return mapper.selectAll();
}
}
在控制器中使用到了图片的文件上传以及页面传递的日期格式,所以需要写一个工具类。
工具类BaseController.java
该工具类在本案例中放在util包中。
package cn.shq.util;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import java.beans.PropertyEditorSupport;
import java.io.File;
import java.text.ParseException;
import java.util.Date;
public class BaseController extends DateUtils {
//定义真实的上传路径 : 案例中所用到的文件(图片)保存在改目录下。
public final String REAL_PATH = "D:"+ File.separator+"uploadImg"+File.separator;
//访问路径
public final String VISIT_PATH = File.separator+"upimg"+File.separator;
/**
* 将前台传递过来的日期格式的字符串,自动转化为Date类型
*/
private static String[] parsePatterns = {
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"
};
/**
* 日期型字符串转化为日期 格式
*/
public static Date parseDate(Object str) {
if (str == null)
{
return null;
}
try
{
return parseDate(str.toString(), parsePatterns);
}
catch (ParseException e)
{
return null;
}
}
@InitBinder
public void initBinder(WebDataBinder binder)
{
// Date 类型转换
binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
{
@Override
public void setAsText(String text)
{
setValue(parseDate(text));
}
});
}
}
控制器类BookController.java
package cn.shq.controller;
import cn.shq.model.*;
import cn.shq.service.BookService;
import cn.shq.service.PublishService;
import cn.shq.util.BaseController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Controller
public class BookController extends BaseController {
@Autowired
BookService bookService;
@Autowired
PublishService publishService;
// 应用的上下文路径,也可以称为项目路径
@Value("${server.servlet.context-path}")
String projName; // 将项目路径 注入到 projName中。
/**
* 查询全部
* */
@GetMapping("/books")
public String books(Model model){
List bs = bookService.selectAll();
System.out.println("bs:"+bs);
model.addAttribute("bs",bs);
return "index";
}
/**
* 文件上传
* */
@PostMapping("/doUpload")
@ResponseBody
public Map doUpload(MultipartFile photo) throws IOException {
Map result = new HashMap<>();
//判断是否为空
if(null ==photo){
result.put("type","error");
result.put("msg","请选择上传的图片");
return result;
}
//判断大小
long size = photo.getSize();
if(size > 2000000){
result.put("type","error");
result.put("msg","上传的图片超过限定大小,请上传2M以内的图片!");
return result;
}
//拿到图片的后缀
int index = photo.getOriginalFilename().lastIndexOf(".");
String suffix = photo.getOriginalFilename().substring(index);
//判断后缀是否是图片
if(!".jpg,.jpeg,.png,.gif".toUpperCase().contains(suffix.toUpperCase())){
result.put("type","error");
result.put("msg","必须上传指定格式的图片.jpg,.jpeg,.png,.gif");
return result;
}
//修改文件的名字
String newFileName = System.currentTimeMillis()+""+suffix;
//建立文件 ↓ 因为上面继承了工具类,则可以直接使用this表示。
File file = new File(this.REAL_PATH,newFileName);
//写入磁盘
photo.transferTo(file);//把文件写入到指定的路径中;
//返回给前端数据
result.put("type","success");
result.put("msg","上传成功!");
result.put("fileName",newFileName);
result.put("imgName",projName+File.separator+this.VISIT_PATH+newFileName);
result.put("filePath",this.VISIT_PATH);
return result;
}
/**
* 添加
* 1、点击添加按钮,先执行查询所有的出版社,然后跳往添加的页面。
* 2、执行添加操作。
* */
@GetMapping("/toAdd")
public String toAdd(Model model){
List pubs = publishService.selectAll();
model.addAttribute("pubs",pubs);
return "add";
}
@PostMapping("/doAdd")
public String doAdd(Book book){
bookService.insert(book);
return "redirect:/books";
}
//删除
@GetMapping("/doDel/{bookId}")
public String doDel(@PathVariable Integer bookId){
bookService.del(bookId);
return "redirect:/books";
}
/**
* 修改:
* 1、点击修改按钮,先根据ID查询到对应书籍的信息,和出版社信息,跳往修改页面。
* 2、执行修改操作。
* */
@GetMapping("/toUpdate/{bookId}")
public String toUpdate(@PathVariable Integer bookId,Model model){
Book book = bookService.findByID(bookId);
List pubs = publishService.selectAll();
model.addAttribute("book",book);
model.addAttribute("pubs",pubs);
return "update";
}
@PutMapping("/doUpdate")
public String doUpdate(Book book){
bookService.update(book);
return "redirect:/books";
}
}
index.html
首页
添加
图书编号
图书名称
出版社
出版日期
宣传页
操作
图书名称
出版社
出版日期
删除
修改
add.html
添加图书
update.html
修改界面
地址:http://localhost:8088/shq/books
效果:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.7.12
cn.shq
springBoot_CRUD
0.0.1-SNAPSHOT
springBoot_CRUD
springBoot_CRUD
1.8
org.springframework.boot
spring-boot-starter-thymeleaf
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.2.0
org.springframework.boot
spring-boot-devtools
runtime
true
mysql
mysql-connector-java
8.0.25
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.boot
spring-boot-configuration-processor
true
org.webjars
jquery
3.3.1
org.webjars
layui
2.5.6
org.webjars
bootstrap
4.5.2
org.webjars
bootstrap-select
1.13.17
org.webjars
bootstrap-datetimepicker
2.4.4
org.webjars
bootstrap-table
1.16.0
org.webjars
momentjs
2.24.0
org.apache.commons
commons-lang3
3.9
tk.mybatis
mapper-spring-boot-starter
2.1.5
com.alibaba
druid
1.1.10
org.springframework.boot
spring-boot-starter-jdbc
src/main/java
**/*.yml
**/*.properties
**/*.xml
false
src/main/resources
**/*.css
**/*.js
**/*.html
**/*.png
**/*.jpg
**/*.properties
**/*.yml
**/*.xml
**/*.conf
false
org.springframework.boot
spring-boot-maven-plugin
org.projectlombok
lombok