1 概述 如今使用Spring boot+thymeleaf开发Web应用程序,开发周期更短,学习周期也短。本节课程技术采用Spring Boot+thymeleaf+ArrayList组合,可以在学员位不了解Spring Data或不使用数据库访问对象的情况仍然学习好 Spring Boot+thymeleaf 开发CURD程序。
2 依赖 在这种情况下,我们将依赖spring-boot-starter-parent进行简单的依赖关系管理,版本控制和插件配置。
<?xml version="1.0" encoding="UTF-8"?>4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.6.RELEASE com.wangshenghua spring-mvc-curd 0.0.1-SNAPSHOT spring-mvc-curd Demo project for Spring Boot
<properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </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> </build> 3 数据模型层 为避免过多的细节,这里还是使用POJO作为数据模型层。学员可以更专注于thymeleaf。package com.wangshenghua.model;
public class User {
private long id; private String name; private String email; public User() { } public User(long id, String name, String email) { this.id = id; this.name = name; this.email = email; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; }} 4 控制器层 在这一层使用一个类UserController.java却包含数据访问对象(DAO)的功能。
package com.wangshenghua.controller;
import java.util.ArrayList; import java.util.List;
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping;
import com.wangshenghua.model.User;
@Controller public class UserController {
private static List<User> users = new ArrayList<User>(); // 使用List当容器保存数据,来代替数据库 static { users.add(new User(1, "黄志燕", "ssss@qq.com")); users.add(new User(2, "侯慧聪", "hhhh@qq.com")); users.add(new User(3, "王广宏", "gggg@qq.com")); } private long getMaxId() { long id = 0; for (User user : users) { if (user.getId() > id) id = user.getId(); } return id + 1; } private User getUser(long id) { User user = null ; for (User u : users) { if (u.getId() == id) { user = u; break; } } return user; } private void update(User user,long id) { for (User u : users) { if (u.getId() == id) { u.setName(user.getName()); u.setEmail(user.getEmail()); break; } } } private void delete(long id) { for (User u : users) { if (u.getId() == id) { users.remove(u); break; } } } @GetMapping("/allUser") public String allUser(Model model) { model.addAttribute("users", users); return "list-user"; } @GetMapping("/adduser") public String showAddUserForm(Model model) { User user = new User(); user.setId(getMaxId()); model.addAttribute("user", user); return "add-user"; } @PostMapping("/adduser") public String addUser(User user, Model model) { users.add(user); return "redirect:/allUser"; } @GetMapping("/edit/{id}") //{id}是占位符 public String showUpdateForm(@PathVariable("id") long id, Model model) { //@PathVariable 路径变量 User user = getUser(id); model.addAttribute("user", user); return "update-user"; } @PostMapping("/update/{id}") public String updateUser(@PathVariable("id") long id, User user, Model model) { update(user,id); return "redirect:/allUser"; } @GetMapping("/delete/{id}") public String deleteUser(@PathVariable("id") long id, Model model) { delete(id); return "redirect:/allUser"; }} @Controller注释表明UserController.java类是一个控制器。
Spring的控制器默认是单实例,因此List users被设计成静态的,使得它在全生命周期可以使用。而且添加一个静态块用于初始部分数据,这里初始了3条用户信息。
接下来的几个方法代替了DAO层的查找、保存、删除方法。
@GetMapping和@PostMapping分别表示get请求和post请求,相当于Servlet中doGet()方法和doPost()方法。这意味着 @GetMapping和@PostMapping 中的值可以一样。
在方法showUpdateForm()上传的注释中出现了{id},它表示一个占位符,表示路径变量的占位符,其中的id可以是别的字符。而紧跟是注释@PathVariable(“id”) long id,用于获取占位符 {id} 实际传递过来的值。
@PathVariable注释用途非常广泛,在查找、修改、删除等方法中都需要用到。
重定向,通过redirect指示重定向到另一个URL。如”redirect:/allUser” 重定向到请求 /allUser
在showAddUserForm方法中,实例化一个User,并设置好id,然后通过Model的实例传递实例User到视图层add-user.html
5 视图层 视图层在使用thymeleaf模板时,视图层的文件都是.html文件。这对前后端分工合作开发非常好友,前端开发人员不需要懂java编程也能参与到Java开发中来。
thymeleaf模板文件在spring boot工程中统一放置在src/main/resources/templates目录里。这个规则很重要,不遵循会出现404的错误。
list-user.html list-user.html 视图用于遍历所有的用户信息。
用户列表添加新用户
th:switch用于判断,与java中的switch一样,这里判断控制器传递过来的数据。th:case="null" 当没有数据时条件,th:case="*" 当有数据时的条件。th:each="user : ${users}"用于遍历集合里的数据,user是变量,users是控制传递过来的数据。
显示数据使用th:text="${user.name}",user是变量或实例,name是实例的属性。
属性th:href相当于HTML中的a元素的属性href。@{/edit/} 用于指定个相对的URL路径。而 {id}表示路径变量的一个占位符,(id=${user.id}) 用于设置这个id的实际值。
add-user.html add-user.html视图提供一个表单,用于添加user。
添加用户 姓名 邮箱 th:action同HTML中form元素的action属性一样,指向一个处理表单的URL。th:object用于与控制器交互,它的值是控制器传递过来的一个数据模型。这个数据模型可以收集表单的字段。
th:field是HTML中input元素的name属性和value属性的结合体,th:field=”*{name}不仅有属性name,还有属性value。属性name的值是name,value的值是表单中输入的值,或控制器传递过来的数据模型的值。
update-user.html 视图update-user.html提供一个修改数据的表单,它同添加用户的视图一样。
修改用户 姓名 邮箱 6 运行程序 spring boot程序使用嵌入式tomcat作为容器,入口函数是main方法。package com.wangshenghua.config;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = {“com.wangshenghua.*”}) public class SpringMvcCurdApplication {
public static void main(String[] args) { SpringApplication.run(SpringMvcCurdApplication.class, args); }} 这个类在使用STS创建Spring Starter Project时自动生成。
@SpringBootApplication用于指示容器,这是入口处,要运行程序先到这里来。
参数scanBasePackages用于扫描包,它的值是各包名,可以使用能配符*。在多个包的情况下,未指定包扫描的包不会被实例化,不被实例化也就不能在内存里,不能在CPU里执行。
右击工程,在弹出的菜单中选择【Run as】【Spring Boot App】启动工程,在浏览器地址栏输入http://localhost:8080即可访问本程序。
7 总结 本节课程使用Spring Boot和thymeleaf技术实现一个增、删、改、查的小程序。程序虽小,用到的技术却是以后复杂应用的基石。学员位重点掌握控制层各方法的写及视图如何遍历数据、表单的使用。
本节课程源码已经上传到github,可以前往下载。