开头先附上原作者原文连接
https://learner.blog.csdn.net/article/details/88925013
最近准备学习Springboot
所以就找到了大佬Evan-Nightly的“白卷”项目
里面的步骤大部分都很清晰,解释得也很到位
个别问题在评论区都有解决方案
虽然我也很赞同原作者的说法
我真是爱死 JPA 了,用 Mybatis 写 SQL 真的烦(我可不是说 Mybatis 不好用哈)。
但是毕竟刚学习了Mybatis,所以打算将这个项目改成用Mybatis来对SQL进行操作,因为原作者的项目实现了前后端分离,所以更改成Mybatis只对后端有改动,前端几乎没有改动。
另外,本人是跟着原文学到项目(十)之后才进行了更改,本博客的基础是已经实现了项目(十)之前的所有内容(包括项目(十)除了部署之后的内容)
一、导入Mybatis相关依赖
在pom.xml
里面添加以下代码
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
然后在pom.xml
里面中<build>
标签中添加以下内容,这段代码作用是防止我们资源导出失败的问题。里面的src/main/resources
就是我们做项目的时候配置文件存放的地方,这段代码的大意就是在编译的时候将会带上src/main/resources
里边的properties
、xml
、yml
文件。
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
二、修改配置文件
- 首先删除原来项目中的
application.properties
文件 - 在
src/main/resources
下创建配置文件application.yml
,如图
里面的内容如下
spring
profiles:
active: dev
#这里为什么使用dev,后面会解释
- 在同级目录下创建配置文件
application-dev.yml
server:
port: 8080
#注意事项:1.用户名和密码改成自己数据库的用户名跟密码;2.url中的‘database’改成自己的数据库名字,“白卷”项目实战教程中的数据库名字是white_jotter
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapping/*.xml
type-aliases-package: com.example.demo.entity
#showSql
logging:
level:
com.example.demo.mapper: debug
在这里补充两点小知识:
1).yml
的基本语法有以下几点:对大小写很敏感;使用缩进来表示层级关系,具体缩进的空格数不重要,相同层级的元素左对齐即可(如上面中的username
和password
);缩进不允许使用tab
,只能使用空格;#
用来表示注释
2)在Springboot中多环境的配置文件名都要满足格式application-{profile}.yml
,上文使用到的application-dev.yml
对应的是开发环境
,其他的环境有:
application-test.yml 测试环境
application-prod.yml 生产环境
三、修改后端代码
修改主要涉及以下几个类和接口,为了阅读方便所以我把dao
改成了mapper
还添加了三个映射文件
BookMapping.xml
CategoryMapping.xml
UserMaping.xml
不着急,我们一步步来,首先是三个接口
BookMapper.java
package com.hong.wj.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.hong.wj.pojo.Book;
import com.hong.wj.pojo.Category;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @Author hong
* @Date 2022/2/22 21:20
* @Version 1.0
*/
//这里主要是添加了一个通过Id搜索book
//然后把添加book和修改book分开成了两个方法
//“按照标题或作者查找”的参数只保留了一个
@Component
@Mapper
public interface BookMapper {
List<Book> selectByCategory(Category category);
List<Book> selectAllByTitleLikeOrAuthorLike(String keyword1);
public List<Book> selectAll();
public void deleteById(int id);
public Book selectById(int id);
public void addBook(Book book);
public void updateBook(Book book);
}
CategoryMapper.java
package com.hong.wj.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.data.domain.Sort;
import com.hong.wj.pojo.Category;
import org.springframework.stereotype.Component;
import java.util.List;
//这个主要是改了名字(dao -> mapper),没什么其他改动
@Component
@Mapper
public interface CategoryMapper {
public List<Category> selectAll(Sort sort);
public Category SelectById(int id);
}
UserMapper.java
package com.hong.wj.mapper;
import com.hong.wj.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;
//这个接口目前只有登陆验证的作用,新添用户功能尚未实现,不过写在这里也暂时没什么影响
@Component
@Mapper
public interface UserMapper {
User selectByUsername(String username);
User selectByUsernameAndPassword(String username,String password);
void addUser(User user);
}
写完这三个接口接下来我们要去编写xml映射文件了,数据库还是用原来的数据库就行,无需改动
BookMapping.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.hong.wj.mapper.BookMapper">
<resultMap id="BookResultMap" type="com.hong.wj.pojo.Book">
<id column="id" property="id"/>
<result column="cover" property="cover"/>
<result column="title" property="title"/>
<result column="author" property="author"/>
<result column="date" property="date"/>
<result column="press" property="press"/>
<result column="abs" property="abs"/>
<association property="category" javaType="com.hong.wj.pojo.Category" column="cid">
<id column="c_id" property="id"/>
<result column="c_name" property="name"/>
</association>
</resultMap>
<select id="selectById" parameterType="int" resultMap="BookResultMap">
select b.id, cover, title, author, date, press, abs, c.id c_id, c.name c_name from book b
left join category c
on c.id = b.cid
where b.id = #{id}
</select>
<select id="selectByCategory" parameterType="com.hong.wj.pojo.Category" resultMap="BookResultMap">
select b.id, cover, title, author, date, press, abs, c.id c_id, c.name c_name from book b
left join category c
on c.id = b.cid
where b.cid = #{id}
</select>
<!--这里使用concat来给keyword添加通配符,如果先添加通配符%再传进来的话并不能使%起到通配符的作用-->
<select id="selectAllByTitleLikeOrAuthorLike" parameterType="String" resultMap="BookResultMap">
select b.id, cover, title, author, date, press, abs, c.id c_id, c.name c_name from book b
left join category c
on c.id = b.cid
where title like concat('%',#{keyword1},'%') or Author like concat('%',#{keyword1},'%')
</select>
<select id="selectAll" resultMap="BookResultMap">
select b.id, cover, title, author, date, press, abs, c.id c_id, c.name c_name from book b
left join category c
on c.id = b.cid
</select>
<delete id="deleteById" parameterType="Integer">
delete from book where id = #{id}
</delete>
<insert id="addBook" parameterType="com.hong.wj.pojo.Book">
insert into book (cover, title, author, date, press, abs, cid)
values (#{cover}, #{title}, #{author}, #{date}, #{press}, #{abs}, #{category.id});
</insert>
<update id="updateBook" parameterType="com.hong.wj.pojo.Book">
update book set cover = #{cover}, title = #{title}, author = #{author}, date = #{date}, press = #{press}, abs = #{abs}, cid = #{category.id}
where id = #{id}
</update>
</mapper>
CategoryMapping.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.hong.wj.mapper.CategoryMapper">
<select id="selectAll" resultType="com.hong.wj.pojo.Category">
select * from category
</select>
<select id="SelectById" resultType="com.hong.wj.pojo.Category">
select * from category where id = #{id}
</select>
</mapper>
UserMapping.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.hong.wj.mapper.UserMapper">
<select id="selectByUsername" resultType="com.hong.wj.pojo.User">
select * from user where username = #{username}
</select>
<select id="selectByUsernameAndPassword" resultType="com.hong.wj.pojo.User">
select * from user where username = #{username} and password = #{password}
</select>
<insert id="addUser" parameterType="com.hong.wj.pojo.User">
insert into user(id, username, password) values (#{id}, #{username}, #{password})
</insert>
</mapper>
之后我们要去service层实现这三个mapper,本博客里面个别方法名有一点点小改动,但都是跟映射文件里面的是对应相同的
BookService.java
这里面的有几个小改动:把add
和update
分开了;search
方法里面的参数有改动;名字从dao
改成了mapper
这个后面就不说 ;查找全部book没有了排序sort我也忘了什么时候删掉了,不管了
package com.hong.wj.service;
import com.hong.wj.mapper.BookMapper;
import com.hong.wj.pojo.Book;
import com.hong.wj.pojo.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookService {
@Autowired
BookMapper bookMapper;
@Autowired
CategoryService categoryService;
//查找所有book
public List<Book> list(){
return bookMapper.selectAll();
}
//根据id查找book
public Book selectById(int id){
return bookMapper.selectById(id);
}
//添加book
public void add(Book book){
bookMapper.addBook(book);
}
//更新book
public void updateBook(Book book){
bookMapper.updateBook(book);
}
//根据id删除书籍
public void deleteById(int id){
bookMapper.deleteById(id);
}
//根据分类查找书籍
public List<Book> listByCategory(int cid){
Category category = categoryService.get(cid);
System.out.println("cid = " + cid);
return bookMapper.selectByCategory(category);
}
public List<Book> Search(String keyword){
return bookMapper.selectAllByTitleLikeOrAuthorLike(keyword);
}
}
CategoryService.java
package com.hong.wj.service;
import com.hong.wj.mapper.CategoryMapper;
import com.hong.wj.pojo.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class CategoryService {
@Autowired
CategoryMapper categoryMapper;
//查找所有分类
public List<Category> list(){
Sort sort = new Sort(Sort.Direction.DESC, "id");
return categoryMapper.selectAll(sort);
}
//根据id获取分类
public Category get(int id){
Category c = categoryMapper.SelectById(id);
return c;
}
}
UserService.java
package com.hong.wj.service;
import com.hong.wj.mapper.UserMapper;
import com.hong.wj.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Autowired
UserMapper userMapper;
//判断用户是否存在
public boolean isExist(String username){
User user = getByName(username);
return null!=user;
}
//通过用户名获取用户
public User getByName(String username){
return userMapper.selectByUsername(username);
}
//通过用户名和密码获取用户
public User get(String username, String password){
return userMapper.selectByUsernameAndPassword(username,password);
}
//添加用户
public void add(User user){
userMapper.addUser(user);
}
}
service层除了BookService
其他两个变化不大,
最后我们把目光放回到LibraryController
,先上源码
package com.hong.wj.controller;
import com.hong.wj.pojo.Book;
import com.hong.wj.service.BookService;
import com.hong.wj.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
@RestController
public class LibraryController {
@Autowired
BookService bookService;
@CrossOrigin
@GetMapping("/api/books")
public List<Book> list(){
return bookService.list();
}
@CrossOrigin
@PostMapping("/api/books")
public Book addOrUpdate(@RequestBody Book book){
if(Objects.equals(null, bookService.selectById(book.getId()))){
bookService.add(book);
System.out.println("add a new book");
}
else{
bookService.updateBook(book);
System.out.println("update an old book");
}
return book;
}
@CrossOrigin
@PostMapping("/api/delete")
public void delete(@RequestBody Book book){
bookService.deleteById(book.getId());
}
@CrossOrigin
@GetMapping("/api/categories/{cid}/books")
public List<Book> listByCategory(@PathVariable("cid") int cid) throws Exception{
if(0 != cid){
return bookService.listByCategory(cid);
}else {
return list();
}
}
@CrossOrigin
@GetMapping("/api/search")
public List<Book> searchResult(@RequestParam("keywords") String keywords){
if("".equals(keywords)){
return bookService.list();
}else
return bookService.Search(keywords);
}
@CrossOrigin
@PostMapping("api/covers")
public String coversUpload(MultipartFile file){
String folder = "D:/workspace/img";
File imageFolder = new File(folder);
File f = new File(imageFolder, StringUtils.getRandomString(6)
+ file.getOriginalFilename()
.substring(file.getOriginalFilename()
.length() - 4));
if(!f.getParentFile().exists()){
f.getParentFile().mkdirs();
}
try {
file.transferTo(f);
String imgURL = "http://localhost:8443/api/file/"+f.getName();
return imgURL;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
这个类最大的改动就是addOrUpdate
方法,添加了一个判断逻辑:如果数据库没有这本书,就调用新增(add)方法;否则调用修改(update)方法。
四、运行测试
前后端都运行,然后打开http://localhost:8080/login
账号:admin
密码:123
可以成功进到首页,没有问题
点进图书馆,也没有问题(图书的封面名字都是乱编的,请勿在意 )
接下来按照增删改查的顺序来试一遍
增
删
改
查
总体检查下来没有什么大毛病,JPA改Mybatis到此就基本成功了。其他一些项目的小毛病大家去原项目的评论区都有很好的解决方案,最后再次附上原项目链接!
https://learner.blog.csdn.net/article/details/88925013