目录
一、环境配置
软件依赖
- Idea
- JDK20
- Mysql8.0
- bootstrap
Spring boot 框架依赖项
- Lombok
- Spring Boot
- DevToolsSpring Web
- Thymeleaf
- Spring Data
-
JPAMySQL Driver
二、实体类
对于java来说单个表可以用一个类来存储元数据,每一行数据则由这个类的对象存储。使用@Entity将该类注册为实体类,将数据映射到数据库的数据表中。映射关系由@Table指定。
Teacher 类
@Data
@Entity
@Table(name = "tb_teacher")
public class Teacher {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private long teaId;
@Column
private String teaName;
@Column
private String gender;
@Column
private String birth;
@Column
private String position;
@Override
public String toString() {
return teaName;
}
}
Student类
@Data
@Proxy(lazy = false)
@Entity
@Table(name = "tb_student")
public class Student {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private long stuId;
@Column
private String className;
@Column
private String name;
@Column
private String gender;
@Column
private String birth;
}
Classes类
@Data
@Entity
@Table(name = "tb_classes")
public class Classes {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private long classId;
@Column
private String className;
@Column
private String teacher;
@Override
public String toString() {
return className;}
}
三、Repository层
repository是指数据仓库的意思。Repository居于业务层和数据层之间,将两者隔离开来,在它的内部封装了数据查询和存储的逻辑,降低层级之间的耦合,更换、升级ORM引擎并不会影响原有的业务逻辑代码。以下是三个实体的接口。
//Classes
public interface ClassesRepository extends JpaRepository<Classes,Long>{}
//Student
public interface StudentRepository extends JpaRepository<Student,Long> {
List<Student> findAllByName(String name);
}
//Teacher
public interface TeacherRepository extends JpaRepository<Teacher,Long> {
List<Teacher> findAllByTeaName(String name);
}
四、Service
Service层的主要作用是将Controller层传递的请求转化为具体的数据操作,与Repository层配合完成具体的数据存储和访问。同时,Service层还负责一些逻辑的处理,例如数据校验、逻辑计算等。我将Service层分为两步实现,第一步定义每个类的接口,在接口中规范功能的实现。第二步实现接口。
ClassesService
public interface ClassesService {
List<Classes> getAllClasses();
void saveClasses(Classes classes);
Classes getClassesById(long id);
void deleteClassesById(long id);
Page<Classes> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);
}
ClassesServiceImp
@Service
public class ClassesServiceImp implements ClassesService {
@Autowired
private ClassesRepository classesRepository;
@Override
public List<Classes> getAllClasses() {
return classesRepository.findAll();
}
@Override
public void saveClasses(Classes classes) {
classesRepository.save(classes);
}
@Override
public Classes getClassesById(long id) {
Optional<Classes> optional = classesRepository.findById(id);
Classes classes;
if (optional.isPresent()) {
classes = optional.get();
} else {
throw new RuntimeException(" 找不到班级ID :: " + id);
}
return classes;
}
@Override
public void deleteClassesById(long id) {
classesRepository.deleteById(id);
}
@Override
public Page<Classes> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortField).ascending()
: Sort.by(sortField).descending();
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
return this.classesRepository.findAll(pageable);
}
}
StudentService
public interface StudentService {
List<Student> getAllStudent();
void saveStudent(Student student);
Student getStudentById(long id);
void deleteStudentById(long id);
List<Student> findAllByName(String name);
Page<Student> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);
}
StudentServiceImp
@Service
public class StudentServiceImp implements StudentService {
@Autowired
private StudentRepository studentRepository;
@Override
public List<Student> getAllStudent() {
return studentRepository.findAll();
}
@Override
public void saveStudent(Student Student) {
studentRepository.save(Student);
}
@Override
public Student getStudentById(long id) {
Optional<Student> optional = studentRepository.findById(id);
Student student;
if (optional.isPresent()) {
student = optional.get();
} else {
throw new RuntimeException(" 找不到学生ID :: " + id);
}
return student;
}
@Override
public void deleteStudentById(long id) {
studentRepository.deleteById(id);
}
@Override
public List<Student> findAllByName(String name) {
return studentRepository.findAllByName(name);
}
@Override
public Page<Student> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortField).ascending()
: Sort.by(sortField).descending();
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
return this.studentRepository.findAll(pageable);
}
}
TeacherService
public interface TeacherService {
List<Teacher> getAllTeacher();
void saveTeacher(Teacher teacher);
Teacher getTeacherById(long id);
void deleteTeacherById(long id);
List<Teacher> findAllByTeaName(String name);
Page<Teacher> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);
}
TeacherServiceImp
@Service
public class TeacherServiceImp implements TeacherService {
@Autowired
private TeacherRepository teacherRepository;
@Override
public List<Teacher> getAllTeacher() {
return teacherRepository.findAll();
}
@Override
public void saveTeacher(Teacher teacher) {
teacherRepository.save(teacher);
}
@Override
public Teacher getTeacherById(long id) {
Optional< Teacher > optional = teacherRepository.findById(id);
Teacher teacher;
if (optional.isPresent()) {
teacher = optional.get();
} else {
throw new RuntimeException(" 找不到老师ID :: " + id);
}
return teacher;
}
@Override
public void deleteTeacherById(long id) {
teacherRepository.deleteById(id);
}
@Override
public List<Teacher> findAllByTeaName(String name) {
return teacherRepository.findAllByTeaName(name);
}
@Override
public Page<Teacher> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
Sort sort = sortDirection.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortField).ascending()
: Sort.by(sortField).descending();
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
return this.teacherRepository.findAll(pageable);
}
}
五、Controller层
从HTTP请求中获取信息,提取参数,并将其分发给不同的处理服务(service层),并向前端返回service层处理后的数据。
ClassesController
@Controller
public class ClassesController {
@Autowired
private ClassesService classesService;
@GetMapping("/class")
public String viewHomePage(Model model) {
return this.findPaginated(1, "className", "asc", model);
}
@GetMapping("/NewClassesForm")
public String NewClassesForm(Model model) {
Classes classes = new Classes();
model.addAttribute("classes", classes);
return "new_classes";
}
@PostMapping("/saveClasses")
public String saveClasses(@ModelAttribute("classes") Classes classes) {
classesService.saveClasses(classes);
return "redirect:/class";
}
@GetMapping("/classFormForUpdate/{id}")
public String FormForUpdate(@PathVariable(value = "id") long id, Model model) {
Classes classes = classesService.getClassesById(id);
model.addAttribute("classes", classes);
return "update_classes";
}
@GetMapping("/deleteClasses/{id}")
public String deleteClasses(@PathVariable(value = "id") long id) {
classesService.deleteClassesById(id);
return "redirect:/class";
}
//获取分页数据
@GetMapping("/classpage/{pageNo}")
public String findPaginated(@PathVariable (value = "pageNo") int pageNo,
@RequestParam("sortField") String sortField,
@RequestParam("sortDir") String sortDir,
Model model) {
int pageSize = 10;
Page<Classes> page = classesService.findPaginated(pageNo, pageSize, sortField, sortDir);
List<Classes> listClasses = page.getContent();
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
model.addAttribute("listClasses", listClasses);
return "index_classes";
}
}
StudentController
@Controller
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping("/student")
public String viewHomePage(Model model) {
return this.findPaginated(1, "name", "asc", model);
}
@GetMapping("/NewStudentForm")
public String NewStudentForm(Model model) {
Student student = new Student();
model.addAttribute("student", student);
return "new_student";
}
@PostMapping("/saveStudent")
public String saveStudent(@ModelAttribute("student") Student student) {
studentService.saveStudent(student);
return "redirect:/student";
}
@GetMapping("/studentFormForUpdate/{id}")
public String FormForUpdate(@PathVariable(value = "id") long id, Model model) {
Student student = studentService.getStudentById(id);
model.addAttribute("student", student);
return "update_student";
}
@GetMapping("/deleteStudent/{id}")
public String deleteStudent(@PathVariable(value = "id") long id) {
studentService.deleteStudentById(id);
return "redirect:/student";
}
@GetMapping("/queryStudent{newname}")
public String query(@PathVariable(value = "newname") String name, Model model) {
List<Student> listStudent = studentService.findAllByName(name);
model.addAttribute("listStudent", listStudent);
return "index_student";
}
//获取分页数据
@GetMapping("/studentpage/{pageNo}")
public String findPaginated(@PathVariable (value = "pageNo") int pageNo,
@RequestParam("sortField") String sortField,
@RequestParam("sortDir") String sortDir,
Model model) {
int pageSize = 10;
Page<Student> page = studentService.findPaginated(pageNo, pageSize, sortField, sortDir);
List<Student> listStudent = page.getContent();
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
model.addAttribute("listStudent", listStudent);
return "index_student";
}
}
TeacherController
@Controller
public class TeacherController {
@Autowired
private TeacherService teacherService;
@GetMapping("/")
public String index(){
return "index";
}
@GetMapping("/teacher")
public String viewHomePage(Model model) {
return this.findPaginated(1, "teaName", "asc", model);
}
@GetMapping("/NewTeacherForm")
public String NewTeacherForm(Model model) {
Teacher teacher = new Teacher();
model.addAttribute("teacher", teacher);
return "new_teacher";
}
@PostMapping("/saveTeacher")
public String saveTeacher(@ModelAttribute("teacher") Teacher teacher) {
teacherService.saveTeacher(teacher);
return "redirect:/teacher";
}
@GetMapping("/teacherFormForUpdate/{id}")
public String FormForUpdate(@PathVariable(value = "id") long id, Model model) {
Teacher teacher = teacherService.getTeacherById(id);
model.addAttribute("teacher", teacher);
return "update_teacher";
}
@GetMapping("/deleteTeacher/{id}")
public String deleteStudent(@PathVariable(value = "id") long id) {
teacherService.deleteTeacherById(id);
return "redirect:/teacher";
}
@GetMapping("/queryTeacher{newname}")
public String query(@PathVariable(value = "newname") String newname, Model model) {
List<Teacher> listTeacher = teacherService.findAllByTeaName(newname);
model.addAttribute("listTeacher", listTeacher);
return "index_teacher";
}
//获取分页数据
@GetMapping("/teacherpage/{pageNo}")
public String findPaginated(@PathVariable (value = "pageNo") int pageNo,
@RequestParam("sortField") String sortField,
@RequestParam("sortDir") String sortDir,
Model model) {
int pageSize = 10;
Page<Teacher> page = teacherService.findPaginated(pageNo, pageSize, sortField, sortDir);
List<Teacher> listTeacher = page.getContent();
model.addAttribute("currentPage", pageNo);
model.addAttribute("totalPages", page.getTotalPages());
model.addAttribute("totalItems", page.getTotalElements());
model.addAttribute("sortField", sortField);
model.addAttribute("sortDir", sortDir);
model.addAttribute("reverseSortDir", sortDir.equals("asc") ? "desc" : "asc");
model.addAttribute("listTeacher", listTeacher);
return "index_teacher";
}
}
indexController
//用于处理通用请求。
@Controller
public class indexController {
@GetMapping("/bootstrap.min.css")
public String css(){
return "bootstrap.min.css";
}
@GetMapping("/hello")
public String hello(){
return "hello";
}
}
六、前端网页设计(teacher类为例)
index_teacher
用于查询,展示teacher表的数据。
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>...</title>
<link rel="stylesheet" href="http://127.0.0.1:8080/bootstrap.min.css" >
</head>
<body>
<div class="my-1">
<!-- <a th:href = "@{/NewTeacherForm}" class="btn btn-primary btn-sm mb-3"> Add teacher </a> -->
<nav class="navbar navbar-light bg-light">
<form id="query-form" action="/queryTeacher" method="get">
<h6 class="text-secondary">查询名字</h6><input type="text" id="name-input" name="teaName" placeholder="名字">
<button type="button" class="btn btn-info"onclick="queryBookstore()">搜索</button>
</form>
<script>
function queryBookstore() {
var teacher = document.getElementById("name-input").value;
var url = "/queryTeacher" + encodeURIComponent(teacher);
window.location.href = url;
}
</script>
</nav>
<table border="1" class = "table table-striped table-responsive-md">
<thead>
<tr>
<th>
<a th:href="@{'/studentpage/' + ${currentPage} + '?sortField=teaName&sortDir=' + ${reverseSortDir}}">
名字</a>
</th>
<th>
<a th:href="@{'/studentpage/' + ${currentPage} + '?sortField=position&sortDir=' + ${reverseSortDir}}">
职称</a>
</th>
<th>
<a th:href="@{'/studentpage/' + ${currentPage} + '?sortField=gender&sortDir=' + ${reverseSortDir}}">
性别</a>
</th>
<th>
<a th:href="@{'/studentpage/' + ${currentPage} + '?sortField=birth&sortDir=' + ${reverseSortDir}}">
出生日期</a>
</th>
<th> 操作 </th>
</tr>
</thead>
<tbody>
<tr th:each="Teacher : ${listTeacher}">
<td th:text="${Teacher.teaName}"></td>
<td th:text="${Teacher.position}"></td>
<td th:text="${Teacher.gender}"></td>
<td th:text="${Teacher.birth}"></td>
<td> <a th:href="@{/teacherFormForUpdate/{id}(id=${Teacher.teaId})}" class="btn btn-primary">编辑</a>
<a th:href="@{/deleteTeacher/{id}(id=${Teacher.teaId})}" class="btn btn-danger">删除</a>
</td>
</tr>
</tbody>
</table>
<div th:if = "${totalPages > 1}">
<div class = "row col-sm-10">
<div class = "col-sm-3">
Total Rows: [[${totalItems}]]
</div>
<div class = "col-sm-5">
<span th:each="i: ${#numbers.sequence(1, totalPages)}">
<a th:if="${currentPage != i}" th:href="@{'/classpage/' + ${i}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">[[${i}]]</a>
<span th:unless="${currentPage != i}">[[${i}]]</span>
</span>
</div>
<div class = "col-sm-1">
<a th:if="${currentPage < totalPages}" th:href="@{'/classpage/' + ${currentPage + 1}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">Next</a>
<span th:unless="${currentPage < totalPages}">Next</span>
</div>
<div class="col-sm-1">
<a th:if="${currentPage < totalPages}" th:href="@{'/classpage/' + ${totalPages}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">Last</a>
<span th:unless="${currentPage < totalPages}">Last</span>
</div>
</div>
</div>
</div>
</body>
</html>
new_teacher
用于创建表单信息传回后端,后端处理后存入数据库。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>...</title>
<link rel="stylesheet" href="http://127.0.0.1:8080/bootstrap.min.css" >
</head>
<body>
<div>
<h2>创建老师信息</h2>
<form action="#" th:action="@{/saveTeacher}" th:object="${teacher}" method="POST">
<input type="text" th:field="*{teaName}" placeholder="姓名" class="form-control mb-4 col-4" required="required">
<input type="text" th:field="*{position}" placeholder="职称" class="form-control mb-4 col-4" required="required">
<input type="date" th:field="*{birth}" placeholder="出生日期" class="form-control mb-4 col-4" required="required">
<select type="text" th:field="*{gender}" placeholder="性别" class="form-control mb-4 col-1" required="required">
<option selected value="男">男</option>
<option value="女">女</option>
</select>
<button type="submit" class="btn btn-info col-2"> 提交 </button>
</form>
<hr>
<a th:href="@{/student}"> 返回学生信息页 </a>
</div>
</body>
</html>
update_teacher
向后端请求数据,前端修改后重新传回后端处理。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>...</title>
<link rel="stylesheet" href="http://127.0.0.1:8080/bootstrap.min.css" >
</head>
<body>
<div >
<h2>编辑信息</h2>
<form action="#" th:action="@{/saveTeacher}" th:object="${teacher}" method="POST">
<input type="hidden" th:field="*{teaId}" />
<input type="text" th:field="*{teaName}" class="form-control mb-4 col-4">
<input type="text" th:field="*{position}" class="form-control mb-4 col-4">
<input type="date" th:field="*{birth}" class="form-control mb-4 col-4">
<select type="text" th:field="*{gender}" class="form-control mb-4 col-1">
<option selected value="男">男</option>
<option value="女">女</option>
</select>
<button type="submit" class="btn btn-info col-2"> 保存 </button>
</form>
<hr>
<a th:href="@{/teacher}"> 返回班级信息页</a>
</div>
</body>
</html>
Index
所有的功能页集成到此页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Home</title>
</head>
<body>
<div class="sidebar sidebar-hide-to-small sidebar-shrink sidebar-gestures">
<div class="nano">
<div class="nano-content">
<ul>
<li class="label">班级管理系统</li>
<li><a class="sidebar-sub-toggle"><i class="ti-bar-chart-alt"></i> 学生 <span class="sidebar-collapse-icon ti-angle-down"></span></a>
<ul>
<li><a href="http://127.0.0.1:8080/student" target="index">学生信息</a></li>
<li><a href="http://127.0.0.1:8080/NewStudentForm"target="index">添加信息</a></li>
</ul>
</li>
<li><a class="sidebar-sub-toggle"><i class="ti-bar-chart-alt"></i> 老师 <span class="sidebar-collapse-icon ti-angle-down"></span></a>
<ul>
<li><a href="http://127.0.0.1:8080/teacher"target="index">老师信息</a></li>
<li><a href="http://127.0.0.1:8080/NewTeacherForm"target="index">添加信息</a></li>
</ul>
</li>
<li><a class="sidebar-sub-toggle"><i class="ti-bar-chart-alt"></i> 班级 <span class="sidebar-collapse-icon ti-angle-down"></span></a>
<ul>
<li><a href="http://127.0.0.1:8080/class"target="index">班级信息</a></li>
<li><a href="http://127.0.0.1:8080/NewClassesForm"target="index">添加信息</a></li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="content-wrap">
<iframe style="height: 100%;width: 100%;padding: 0;margin: 0;" frameborder="0" name="index" src="hello">
</iframe>
</div>
</body>
</html>