目录
开发service层、前端页面流程
domain 实体类
还有一个放在domain的实体类Book
public class Book {
private Integer id;
private String name;
private double price;
private String author;
开发service层
Service 组件
如何开发Service组件:只要定义Service类,并使用@Service注解修饰它即可。
创建一个service接口及其实现类。
实现类代码
然后写上添加、查看 和 删除 方法。业务逻辑先弄假数据。
//添加这个@Service注解,springboot就可以自动扫描这个Service组件的实现类,然后把这个类部署成容器中的bean。
@Service
public class BookServiceImpl implements BookService {
//添加书籍的方法
@Override
public Integer addBook(Book book) {
return 1;
}
//查看所有书籍的方法
@Override
public List<Book> getAllBooks() {
Book book = new Book();
book.setId(1);
book.setName("七龙珠");
book.setAuthor("鸟山明");
book.setPrice(200);
List<Book> listBooks = new ArrayList<>();
listBooks.add(book);
return listBooks;
}
//删除书籍的方法
@Override
public void deleteBookById(Integer id) {
System.err.println("删除书籍成功");
}
}
controller 接口代码
然后 controller 这边再去调用 service 的方法。
具体代码
/*
* 将Service组件注入Controller
* 方式一:(传统):使用@Autowired注解。
* 方式二:(目前主流方式):定义有参数的构造器即可。
*/
//方式二:定义有参数的构造器即可。这个就不需要使用@Autowired注解了。
private BookService bookService;
//这个就是springboot推荐的注入方式,就是利用有参数的构造器
public BookController (BookService bookService){
this.bookService = bookService;
}
//进入bookForm添加书籍页面的方法
@GetMapping("/bookForm")
public String bookForm(){
//在Spring MVC中,当控制器方法返回一个字符串时,它通常被视图解析器解析为一个视图名,而不是一个普通的字符串
//视图解析器会根据配置将这个视图名解析为相应的视图文件,然后进行渲染和返回给客户端
//返回页面--会被视图解析器自动解析为名字为bookForm的视图。
return "bookForm";
}
//添加书籍方法
//映射地址
@PostMapping("/addBook")
public String addBook(Book book,Model model){
Integer integer = bookService.addBook(book);
if (integer>0){
//添加成功,重定向到指定地址(listBooks页面)
return "redirect:listBooks";
}else {
//添加失败,返回原本的添加页面。
model.addAttribute("tip","书籍添加失败");
return "bookForm";
}
}
//查看所有的书籍
@GetMapping("/listBooks")
public String list(Model model){
//查询所有图书数据
List<Book> allBooks = bookService.getAllBooks();
for (Book allBook : allBooks) {
System.err.println(allBook);
}
//存入到books属性中
model.addAttribute("books",allBooks);
//返回视图页面
return "listBooks";
}
//@PathVariable 映射 URL 绑定的占位符,通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过
//删除书籍
@GetMapping("/deleteBook/{id}")
public String deleteBook(@PathVariable Integer id){
bookService.deleteBookById(id);
//重定向到指定地址,要加个/斜杠,表示跳转到根目录下的listBooks这里。
//不加/斜杠的话,就会变成 listBooks 去替换 这个{id},导致路径出错
return "redirect:/listBooks";
}
注意点1:有参构造器介绍及使用
以前习惯用 @autowired 这种注解进行service组件注入。这次用定义的有参数的构造器来试一试
用有参数的构造器来进行注入的优点:
1、避免空指针:使用函数构造注入时,如果依赖无法注入,那么在启动的时候就会报错,而不是运行时才报错。
2、可以添加final,保证依赖不可变。
如 private final BookService bookService;
一旦Controller通过构造函数注入依赖,那么这个依赖关系在Controller实例的生命周期内将不会发生变化。这可以提高代码的可靠性和稳定性。
注意点2:
在Spring MVC中,当控制器方法返回一个字符串时,它通常被视图解析器解析为一个视图名,而不是一个普通的字符串,视图解析器会根据配置将这个视图名解析为相应的视图文件,然后进行渲染和返回给客户端。
注意点3:
删除图书方法中,因为需要接收前端传来的id,等业务逻辑操作完后,重定向到 listBooks 视图,这个时候需要再 /listBooks 前加斜杠,表示重定向时跳转到根目录下的listBooks视图。
如果不在listBooks前面加斜杠,那么在访问删除方法的时候,return 的这个 listBooks 会替换这个参数路径上的 {id} ,导致访问路径出错。
前端页面
1、添加书籍的视图页面 bookForm.html
<!DOCTYPE html>
<!-- HTML引入Thymeleaf ,导入命名空间 , 把thymeleaf的域名加进来就可以使用了-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>添加图书页面</title>
<!-- 导入 webjar 包中的 bootstrap 样式库 -->
<link ref="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<!-- class="container" :相当于类名,就是这个div模块的名字-->
<!-- class="alert alert-primary" : 警报框 -->
<div class="container">
<div th:text="${tip}" class="alert alert-primary">书籍添加失败显示的提示信息</div>
<h2>添加图书</h2>
<!-- submit提交表单的时候,就会走这个addBook方法 -->
<form method="post" th:action="@{/addBook}">
<div class="form-group row">
<label for="name" class="col-sm-3 col-form-label">图书名:</label>
<div class="col-sm-9">
<input type="text" id="name" name="name" class="form-control" placeholder="输入图书名">
</div>
</div>
<div class="form-group row">
<label for="author" class="col-sm-3 col-form-label">作者:</label>
<div class="col-sm-9">
<input type="text" id="author" name="author" class="form-control" placeholder="输入作者">
</div>
</div>
<div class="form-group row">
<label for="price" class="col-sm-3 col-form-label">价格:</label>
<div class="col-sm-9">
<input type="number" step="0.1" id="price" name="price" class="form-control" placeholder="输入价格">
</div>
</div>
<div class="form-group row">
<div class="col-sm-6 text-right">
<button type="submit" class="btn btn-primary">添加</button>
</div>
<div class="col-sm-6">
<button type="reset" class="btn btn-danger">重置</button>
</div>
</div>
</form>
</div>
</body>
</html>
2、书籍列表视图页面 listBooks.html
<!DOCTYPE html>
<!-- HTML引入Thymeleaf ,导入命名空间 , 把thymeleaf的域名加进来就可以使用了-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>书籍列表页面</title>
<!-- 导入 webjar 包中的 bootstrap 样式库 -->
<link ref="stylesheet" th:href="@{/webjars/bootstrap/4.6.0/css/bootstrap.css}">
</head>
<body>
<!-- class="container" :相当于类名,就是这个div模块的名字-->
<!-- class="alert alert-primary" : 警报框 -->
<div class="container">
<table class="table table-hover">
<tr>
<th>书名</th>
<th>价格</th>
<th>作者</th>
<th>删除</th>
</tr>
<!-- 循环迭代 ${books}就是后端传来的集合数据, book就是循环后的变量 -->
<tr th:each="book: ${books}">
<td th:text="${book.name}">书名</td>
<td th:text="${book.price}">价格</td>
<td th:text="${book.author}">作者</td>
<td><a th:href="@{/deleteBook/} + ${book.id}">删除</a> </td>
</tr>
</table>
</div>
</body>
</html>
测试
测试后,添加,查看、删除都能成功执行。