目录
7.1.1电话的编号、保存的名字、对方的年龄、电话号码、电话的IP
8.1.1在网页中可以查询数据库中对应电话的编号、保存的名字、对方的年龄、电话号码、电话的IP
9.在service层创建一个接口PhoneService这个类服务与9.1.PhoneServiceImpl并进行测试:
9.1.1里面定义了方法,例如:将用户的手机信息存进一个列表里、新增手机信息或者更新手机信息、通过查询用户的手机信息存进一个新的列表里,将它们进行分页展示
10.手机通讯录管理系统的界面(new_phone,html)
10.1它使用了Bootstrap框架来实现样式和布局的设置。
10.1.1在页面上,你可以看到一个包含标题和表单的容器。表单中包括了几个输入字段,用于保存手机通讯录中的联系人信息。每个输入字段都有一个占位符和相应的输入类型。
1.功能要求:
包括但不限于功能要求增删改查和分页。以设备管理管理系统App为例:
1.设备:属性至少3个以上,包括并不限于设备类型、设备名称、初始状态……
2.添加设备
3.删除设备
4.更新设备
5.查找设备(自定义查询依据),显示查询结果。
6.分页
7.排序
扩展(加分):例如部门设备(1:n)管理部门,根据部门查询设备等等。
2.背景要求:
设计一个手机通讯管理系统,提供用户方便查找并修改。
3.技术要求:
创建项目,并添加依赖项。
4.添加数据库MySQL
MySQL是一个开源的关系型数据库管理系统,被广泛用于Web应用程序开发。它具有卓越的性能、可靠性和可扩展性,提供了丰富的查询语言和存储过程支持。通过与Spring Boot和JPA的结合,我们可以轻松地进行数据库操作,实现数据的持久化和查询。
我定义的数据名,以及密码,各位可以尝试着修改。数据库名称:testdb
spring.datasource.url=jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username= root
spring.datasource.password= 123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.open-in-view=false
# for Spring Boot 2
# spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect
# for Spring Boot 3
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQLDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto= update
#?????hibernate-sql
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
5.文件准备:
5.1.创建软件包与实现类
6.控制层(PhoneConntroller):
6.1.分页、添加、添加并保持、修改、删除、排序、搜索名字
package com.example.phone.Controller;
import com.example.phone.model.Phone;
import com.example.phone.repository.PhoneRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
/ 控制层
@Controller
public class PhoneController {
@Autowired
private PhoneRepository phoneRepository;
/// 分页
@GetMapping("/")
public String viewHomePage(Model model) {
return findPaginated(1, "name", "asc", model);
}
/// 添加
@GetMapping("/showNewPoneForm")
public String showNewPhoneForm(Model model) {
Phone phone = new Phone();
model.addAttribute("phone", phone);
return "new_phone";
}
/// 添加的保存
@PostMapping("/savePone")
public String savePhone(@ModelAttribute("phone") Phone phone) {
phoneRepository.save(phone);
return "redirect:/";
}
/// 修改
@GetMapping("/showFormForUpdate/{id}")
public String showFormForUpdate(@PathVariable("id") long id, Model model) {
Optional<Phone> optional = phoneRepository.findById(id);
if (optional.isPresent()) {
Phone phone = optional.get();
model.addAttribute("phone", phone);
} else {
throw new RuntimeException("Cannot find phone with ID: " + id);
}
return "update_phone";
}
/// 删除
@GetMapping("/deletePhone/{id}")
public String deletePhone(@PathVariable("id") long id) {
phoneRepository.deleteById(id);
return "redirect:/";
}
排序
@GetMapping("/page/{pageNo}")
public String findPaginated(@PathVariable(value = "pageNo") int pageNo,
@RequestParam("sortField") String sortField,
@RequestParam("sortDir") String sortDir,
Model model) {
int pageSize = 5;
Sort sort = sortDir.equalsIgnoreCase(Sort.Direction.ASC.name())
? Sort.by(sortField).ascending()
: Sort.by(sortField).descending();
Pageable pageable = PageRequest.of(pageNo - 1, pageSize, sort);
Page<Phone> page = phoneRepository.findAll(pageable);
List<Phone> listPhones = 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("listPhones", listPhones);
return "index";
}
//搜索名字
@GetMapping("/query{inpname}")
public String query(@PathVariable(value = "inpname") String inpame,Model model){
List<Phone> listPhones = phoneRepository.findByName(inpame);
model.addAttribute("listPhones",listPhones);
return "index";
}
}
7.业务类(Phone):
7.1.在此定义了5个业务类的属性:
7.1.1电话的编号、保存的名字、对方的年龄、电话号码、电话的IP
package com.example.phone.model;
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
@Table(name = "phones")
public class Phone {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "numbering") /// 电话的编号
private String numbering;
@Column(name = "name") 保存的名字
private String name;
@Column(name = "age") 对方的年龄
private String age;
@Column(name = "phone") 电话号码
private String phone;
@Column(name = "address") / 电话的IP
private String address;
}
8.数据访问层(PhoneRepository)接口:
8.1.负责与数据的查询的方法
8.1.1在网页中可以查询数据库中对应电话的编号、保存的名字、对方的年龄、电话号码、电话的IP
package com.example.phone.repository;
import com.example.phone.model.Phone;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
接口
@Repository
public interface PhoneRepository extends JpaRepository<Phone, Long> {
/// 添加查询名字
@Query("select p from Phone p where p.name like %:name%")
List<Phone> findByName(@Param("name") String name);
}
9.在service层创建一个接口PhoneService这个类服务与9.1.PhoneServiceImpl并进行测试:
9.1.1里面定义了方法,例如:将用户的手机信息存进一个列表里、新增手机信息或者更新手机信息、通过查询用户的手机信息存进一个新的列表里,将它们进行分页展示
package com.example.phone.service;
import com.example.phone.model.Phone;
import org.springframework.data.domain.Page;
import java.util.List;
public interface PhoneService {
//获取所有的手机通讯信息
List<Phone> getAllPhones();
//新增/更新一个手机通讯信息
void savePhone(Phone phone);
//获取指定ID的手机通讯信息
Phone getPhoneById(long id);
//删除指定ID的手机通讯信息
void deletePhoneById(long id);
/// 查询指定名字
List<Phone> findByNameContaining(String name);
//分页查询手机通讯信息
Page<Phone> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection);
}
9.1.2:测试类BankServiceimpl用来继承BankService,实现获取所有用户的手机信息、根据姓名查找用户的、保存用户信息到列表、根据id删除用户的信息、根据姓名查找列表是否存在此用户、设置排序参数:
package com.example.phone.service;
import com.example.phone.model.Phone;
import com.example.phone.repository.PhoneRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class PhoneServiceImpl implements PhoneService {
private PhoneRepository phoneRepository;
@Autowired
public PhoneServiceImpl(PhoneRepository phoneRepository){
this.phoneRepository = phoneRepository;
}
@Override
public List<Phone> getAllPhones() {
return phoneRepository.findAll();
}
@Override
public void savePhone(Phone phone) {
phoneRepository.save(phone);
}
@Override
public Phone getPhoneById(long id) {
Optional<Phone> optional = phoneRepository.findById(id);
Phone phone = null;
if (optional.isPresent()) {
phone = optional.get();
} else {
throw new RuntimeException("找不到手机ID:" + id);
}
return phone;
}
@Override
public void deletePhoneById(long id) {
phoneRepository.deleteById(id);
}
@Override
public List<Phone> findByNameContaining(String name) {
List<Phone> optional = phoneRepository.findByName(name);
return optional;
}
@Override
public Page<Phone> findPaginated(int pageNo, int pageSize, String sortField, String sortDirection) {
//设置排序参数,升序ASC/降序DESC?
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.phoneRepository.findAll(pageable);
}
}
10.HTML部分:主页面以及新增和更新部分页面设置
10.1主页面(index):
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>手机通讯录管理系统</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container my-2">
<h1>电 话 列 表</h1>
<a th:href = "@{/showNewPoneForm}" class="btn btn-primary btn-sm mb-3"> 添加手机通讯录数据 </a>
<h3>查找名字</h3>
<form id="query-form" action="/query" method="get">
<input type="text" id="name-input" name="inpname" placeholder="输入需要查询的名字">
<button type="button" onclick="queryStudent()">查找</button>
</form>
<!-- 将输入框输入的内容传到url上面去-->
<script>
function queryStudent() {
var name = document.getElementById("name-input").value;
var url = "/query" + encodeURIComponent(name);
window.location.href = url;
}
</script>
<table border="1" class = "table table-striped table-responsive-md">
<thead>
<tr>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=numbering&sortDir=' + ${reverseSortDir}}">
编 号</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=name&sortDir=' + ${reverseSortDir}}">
姓 名</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=age&sortDir=' + ${reverseSortDir}}">
年 龄</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=phone&sortDir=' + ${reverseSortDir}}">
电 话</a>
</th>
<th>
<a th:href="@{'/page/' + ${currentPage} + '?sortField=address&sortDir=' + ${reverseSortDir}}">
地 址</a>
</th>
<th> 操 作 </th>
</tr>
</thead>
<tbody>
<tr th:each="phone : ${listPhones}">
<td th:text="${phone.numbering}"></td>
<td th:text="${phone.name}"></td>
<td th:text="${phone.age}"></td>
<td th:text="${phone.phone}"></td>
<td th:text="${phone.address}"></td>
<td> <a th:href="@{/showFormForUpdate/{id}(id=${phone.id})}" class="btn btn-primary">更新</a>
<a th:href="@{/deletePhone/{id}(id=${phone.id})}" 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="@{'/page/' + ${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="@{'/page/' + ${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="@{'/page/' + ${totalPages}+ '?sortField=' + ${sortField} + '&sortDir=' + ${sortDir}}">Last</a>
<span th:unless="${currentPage < totalPages}">Last</span>
</div>
</div>
</div>
</div>
</body>
</html>
10.手机通讯录管理系统的界面(new_phone,html)
10.1它使用了Bootstrap框架来实现样式和布局的设置。
10.1.1在页面上,你可以看到一个包含标题和表单的容器。表单中包括了几个输入字段,用于保存手机通讯录中的联系人信息。每个输入字段都有一个占位符和相应的输入类型。
在输入字段下方,有一个提交按钮,用于保存输入的联系人信息。
在表单下方,还有一个返回按钮,用于返回到通讯录列表页面。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>手机通讯录管理系统</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>手机通讯录管理系统</h1>
<hr>
<h2>Save Phone</h2>
<form action="#" th:action="@{/savePone}" th:object="${phone}" method="POST">
<input type="text" th:field="*{numbering}" placeholder="编号" class="form-control mb-4 col-4">
<input type="text" th:field="*{name}" placeholder="姓名" class="form-control mb-4 col-4">
<input type="text" th:field="*{age}" placeholder="年龄" class="form-control mb-4 col-4">
<input type="text" th:field="*{phone}" placeholder="电话" class="form-control mb-4 col-4">
<input type="text" th:field="*{address}" placeholder="地址" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> Save Phone</button>
</form>
<hr>
<a th:href="@{/}"> Back to Phone List</a>
</div>
</body>
</html>
11.更新手机通讯录联系人信息的界面:
11.1在更新操作时,通常需要知道要更新的联系人的ID。
这个隐藏字段被用来保存联系人的ID 。通过这个隐藏字段,系统可以识别出要更新的联系人。
除此之外,其他的代码和之前的代码保持一致。用户可以在输入字段中修改联系人的信息,然后点击"Update Phone"按钮来更新联系人信息。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>手机通讯录管理系统</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
</head>
<body>
<div class="container">
<h1>手机通讯录管理系统</h1>
<hr>
<h2>Update Phone</h2>
<form action="#" th:action="@{/savePone}" th:object="${phone}" method="POST">
<!-- Add hidden form field to handle update -->
<input type="hidden" th:field="*{id}" />
<input type="text" th:field="*{numbering}" placeholder="编号" class="form-control mb-4 col-4">
<input type="text" th:field="*{name}" placeholder="姓名" class="form-control mb-4 col-4">
<input type="text" th:field="*{age}" placeholder="年龄" class="form-control mb-4 col-4">
<input type="text" th:field="*{phone}" placeholder="电话" class="form-control mb-4 col-4">
<input type="text" th:field="*{address}" placeholder="地址" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> Update Phone</button>
</form>
<hr>
<a th:href="@{/}"> Back to Phone List</a>
</div>
</body>
</html>
12.运行结果:
12.1.1主页面:
12.1.2 新增页面:
12.1.3 查询页面:
12.1.4 更新、删除:
13. 总结:
该学期JAVA的学习可以说让我们正式认识了JAVA这门语言的魅力,通过结合Spring Boot、JPA、Thymeleaf、MySQL和Bootstrap,从最初几行代码变为现如今的几十行到几百行,一点点的学习一点点的进步,漫长的过程也让我们对知识更深刻的记忆。如老师所言,“代码是需要练的”,光看是无法真正的学会。学习Java高级程序设计课程是一次充实且有收获的经历,通过不懈的努力和持续的学习,我对Java编程语言有了更深入的理解。