一、Web应用项目开发介绍
Web应用项目开发的目标是创建交互性强、功能丰富的应用程序,通过浏览器访问。这些应用可以是电子商务网站、社交媒体平台、在线学习系统、博客和论坛等。开发过程包括设计用户界面、处理数据交互、管理用户身份验证和权限、与数据库交互、实现业务逻辑等。
1.2: Web应用项目开发涉及多个方面的知识和技能
-
前端开发:前端开发主要关注用户界面和用户体验。您可以学习HTML、CSS和JavaScript等技术,掌握网页布局、样式设计和交互效果等。
-
后端开发:后端开发处理服务器端的逻辑和数据存储。您可以学习一种或多种后端语言,如Python、Java、PHP或Ruby等,并了解数据库的基本知识。
-
数据库管理:了解数据库的基本原理和常用的数据库系统,如MySQL、PostgreSQL或MongoDB等。学习如何设计和优化数据库模型,以及如何使用SQL语言进行查询和操作数据。
-
网络和服务器管理:了解网络协议、HTTP通信和服务器配置等内容,以便正确部署和管理Web应用项目。
-
版本控制系统:掌握使用版本控制系统如Git进行代码管理,能够合作开发和管理代码的不同版本。
-
安全性和性能优化:学习如何确保Web应用的安全性,包括用户认证、数据加密和防止常见的网络攻击。此外,了解如何通过优化代码和资源管理来提高Web应用的性能。
1.3:Web应用项目开发学习路线
学习Web应用项目开发的路线可以按照以下步骤进行:
-
学习HTML、CSS和JavaScript:这是Web开发的基础,HTML用于创建网页结构,CSS用于设计页面样式,JavaScript用于实现交互效果和动态功能。您可以通过在线教程、书籍或在线课程学习这些技术。
-
掌握前端框架和库:学习流行的前端框架和库,如React、Vue.js或Angular等,可以帮助您更高效地构建复杂的用户界面和应用逻辑。了解它们的工作原理和基本用法,并实践使用它们开发一些小型项目。
-
学习后端开发语言:选择一种后端开发语言,如Python、Java、Ruby或PHP等,并深入学习该语言的核心概念和语法。了解如何处理HTTP请求、数据存储和服务器端逻辑等。
-
学习数据库管理:学习SQL语言和常见的关系型数据库系统,如MySQL、PostgreSQL或Oracle等。了解如何设计数据库模型、执行查询和更新操作,以及优化数据库性能。
-
学习服务器和网络知识:了解基本的服务器配置和管理,包括Linux操作系统、网络协议、域名系统(DNS)等。学习如何部署Web应用项目到服务器上,并确保安全性和可靠性。
-
学习版本控制和团队协作:了解版本控制系统如Git的基本用法,可以帮助您管理项目代码并与团队成员合作开发。学习分支管理、代码合并和冲突解决等技巧。
-
理解Web应用安全和性能优化:学习常见的Web安全漏洞和攻击方式,并了解如何保护Web应用的安全性。此外,学习如何优化代码和资源,以提高Web应用的性能和响应速度。
-
实践项目开发:通过实际的项目开发经验来巩固所学知识。可以从简单的练习项目开始,逐渐挑战更复杂的实际场景,从而提升自己的技能和经验。
记住,持续的实践和不断的学习是成为一名优秀的Web应用程序员的关键。同时,参与开源项目、阅读技术文档和与其他开发者交流也是提升自己的好方法。
二、Web应用项目开发环境配置
要进行Web应用项目开发,您需要配置以下环境:
-
开发工具和编辑器:选择一种适合您的编程语言和偏好的集成开发环境(IDE)或文本编辑器。一些常见的选择包括Visual Studio Code、PyCharm、Eclipse、Sublime Text等。
-
前端开发环境:对于前端开发,您需要一个浏览器用于调试和测试您的网页。同时,您可以使用Node.js作为运行环境,以便在本地模拟服务器环境。
-
后端开发环境:根据您选择的后端开发语言,需要安装相应的运行时环境和开发工具。例如,如果您选择Python作为后端语言,您需要安装Python解释器和相关的开发工具,如pip包管理器和虚拟环境工具。
-
数据库:如果您的Web应用项目需要使用数据库,您需要安装和配置数据库系统,如MySQL、PostgreSQL、MongoDB等。您还可以选择使用数据库管理工具来方便地管理和操作数据库。
-
版本控制系统:配置一个版本控制系统,如Git,用于管理和跟踪您的代码变更。您可以选择在本地设置Git仓库,或者使用在线的代码托管平台,如GitHub、GitLab或Bitbucket。
-
服务器环境:如果您计划将Web应用部署到生产环境中,您需要配置服务器环境。这包括选择和设置适当的操作系统、Web服务器(如Apache或Nginx)和应用服务器(如Tomcat或Gunicorn)。
-
其他工具和库:根据您的具体项目需求,可能需要安装其他工具和库来支持开发和部署。例如,前端框架(如React或Vue.js)、后端框架(如Django或Ruby on Rails)或其他第三方库。
请注意,具体的环境配置可能因个人偏好、项目需求和技术栈而有所不同。建议在开始之前仔细研究并了解您所选技术栈的相关环境要求,并按照官方文档或社区指南进行配置。
三、Web应用项目开发功能模块的实现
3.1:用户管理模块设计及实现
3.1.1与用户管理需求
对于任何一个管理系统,用户管理功能都是必不可少的。通常,在使用系统之前,用户需要先注册。在使用过程中,往往还存在修改需求,如修改个人联系方式、收货地址等。
在线书店管理系统中主要有两类用户——普通用户和管理员。
-
普通用户的操作包括用户注册、用户登录、用户退出和用户个人信息修改等。
-
管理员的操作包括用户登录、用户退出和用户管理(包括新增普通用户、对普通用户的信息进行编辑和删除普通用户)等。
本章中,我们将实现用户注册、用户登录和用户管理等功能。
普通用户在首次使用系统之前,需要注册,建立个人账户,此时需要提供必要的个人信息,如登录账号、密码、全名、电话、收货地址等,以便完成图书的支付和购买流程。普通用户注册流程如下图所示。
用户登录系统,输入用户名和密码后,系统会验证用户角色,因为系统需要知道此时登录的用户是管理员还是普通用户。若系统验证其为普通用户,则进入普通用户登录后的页面;若是管理员,则进入管理员管理页面;否则,系统提示用户名或密码错误的信息。用户登录流程如下图所示。
本系统有两种角色,一种是管理员,二种是普通用户。管理员可以新增和删除普通用户,并且可以对普通用户的信息进行编辑。用户管理流程如下图:
3.1.2接口需求分析
针对用户管理要求,我们定义如下接口。
-
用户注册接口。
-
接口名称:/registration
-
接口参数:User类的对象
-
返回类型:若注册成功,则返回/login页面;否则,返回registration(注册)页面。
-
用户信息查询接口。
-
接口名称:/profile。利用GET方式获取用户信息。
-
接口参数:用户信息。
-
返回类型:若查询到用户信息,则返回/profile页面。
-
用户信息编辑接口。
-
接口名称:/users/edit/{userId}。
-
接口参数:User类的对象。
-
返回类型:若用户信息修改成功,则返回修改后信息的/profile页面。
-
用户添加接口。
-
接口名称:/user/add。利用POST方式添加用户信息。
-
接口参数:User类的对象。
-
返回类型:若用户添加成功,则返回/addUser页面。
-
用户删除接口
-
接口名称:/users/delete/{userId}。利用DELETE方式删除用户。
-
接口参数:userId(用户ID)。
-
返回类型:返回用户列表(showAllUsers)页面。
3.2后端设计及编码
本节介绍用户域模型设计、Repository实现、用户服务接口实现和控制层实现。
3.2.1用户域模型设计
创建com.book.shop.model包,增加User类,基于user表进行用户域模型的设计,通过定义User类的对象实现序列化。
@Entity
@Table(name = "user")
public class User implements Serializable {
private static final long serialVersionUID =1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY) //定义主键,自增长类型
@Column(name ="userid")
private long userId;
@NotNull
@Size(min =1, max =50)
@Column(name = "username", length =50, unique = true, nullable = false )
private String userName;
@NotNull
@Column(name="password", length = 60) //用户密码
private String userPassword;
@Size(max=50) //用户全名
@Column(name = "fullname",length = 50)
private String userFullname;
@Size(max=50) //用户电话
@Column(name = "phone",length = 50)
private String userPhone;
@Size(max = 120) //用户地址
@Column(name="address",length = 120)
private String userAddress;
@Size(max=80) //用户银行卡号
@Column(name= "bankcard",length = 80)
private String userBankcard;
//建立user表和roles表之间多对多的映射关系
@ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE})
@JoinTable(
name = "permission",
joinColumns = {@JoinColumn(name = "userid",referencedColumnName ="userid")},
inverseJoinColumns = {@JoinColumn(name = "role",referencedColumnName = "rolename")}
)
private Set<Roles> roles =new HashSet<>();
public long getUserId() {
return userId;
}
public void setUserId(long userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserFullname() {
return userFullname;
}
public void setUserFullname(String userFullname) {
this.userFullname = userFullname;
}
public String getUserPhone() {
return userPhone;
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}
public String getUserBankcard() {
return userBankcard;
}
public void setUserBankcard(String userBankcard) {
this.userBankcard = userBankcard;
}
public Set<Roles> getRoles() {
return roles;
}
public void setRoles(Set<Roles> roles) {
this.roles = roles;
}
public User(long userId, String userName, String userPassword, String userFullname, String userPhone, String userAddress, String userBankcard, Set<Roles> roles) {
this.userId = userId;
this.userName = userName;
this.userPassword = userPassword;
this.userFullname = userFullname;
this.userPhone = userPhone;
this.userAddress = userAddress;
this.userBankcard = userBankcard;
this.roles = roles;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"userId=" + userId +
", userName='" + userName + '\'' +
", userPassword='" + userPassword + '\'' +
", userFullname='" + userFullname + '\'' +
", userPhone='" + userPhone + '\'' +
", userAddress='" + userAddress + '\'' +
", userBankcard='" + userBankcard + '\'' +
", roles=" + roles +
'}';
}
//重载equals()方法,实现user类
@Override
public boolean equals(Object obj){
if (this == obj)
return true;
if(!(obj instanceof User)) return false;
User user =(User) obj;
return Objects.equals(getUserId(),user.getUserId());
}
//重载hashCode()方法
@Override
public int hashCode(){
return Objects.hash(getUserId());
}
}
Roles实体
@Data
@Entity
@Table(name = "roles")
public class Roles implements Serializable {
@Id
@Column(name ="rolename")
private String rolename;
}
Order实体
@Data
@Entity
@Table(name = "orders")
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY) //定义主键,自增长类型
@Column(name ="orderid")
private Long orderid;
@NotNull
@Column(name="userid")
private int userId;
@NotNull
@Column(name="orderdate")
private Timestamp orderdate;
@Column(name="status",nullable = false)
private byte status;
@Column(name="totalprice",precision = 5,scale = 1)
private BigDecimal totalprice;
public Order(Long orderid, int userid, Timestamp orderdate, byte status, BigDecimal totalprice) {
this.orderid = orderid;
this.userId = userid;
this.orderdate = orderdate;
this.status = status;
this.totalprice = totalprice;
}
public Order(){
}
3.2.2用户Repository接口
@Repository
public interface UserRepository extends JpaRepository<User,Long> {
public User findByUserName(String userName);
@EntityGraph(attributePaths = "roles")
public User findOneWithRolesByUserName(String userName);
}
RolesRepository接口
@Repository
public interface RolesRepository extends JpaRepository<Roles, String> {
}
OrderRepository接口
@Repository
public interface OrderRepository extends JpaRepository<Order,Long> {
}
3.2.3用户服务接口实现
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private RolesRepository rolesRepository;
@Autowired
private OrderRepository orderRepository;
//通过用户名查找用户
public User findByUserName(String userName){
return userRepository.findByUserName(userName);
}
//注册用户
public User registerUser(User user){
User newUser = new User();
Optional<Roles> role_user = rolesRepository.findById("ROLE_USER");
Roles role = role_user.get();
Set<Roles> roles = new HashSet<>();
BCryptPasswordEncoder encryptedPassword = new BCryptPasswordEncoder();
String encode = encryptedPassword.encode(user.getUserPassword());
newUser.setUserName(user.getUserName());
newUser.setUserPassword(encode);
newUser.setUserFullname(user.getUserFullname());
newUser.setUserPhone(user.getUserPhone());
newUser.setUserAddress(user.getUserAddress());
newUser.setUserBankcard(user.getUserBankcard());
roles.add(role);
newUser.setRoles(roles);
userRepository.save(newUser);
return newUser;
}
//更新用户信息
public void updateUser(User user){
User updateUser = userRepository.findById(user.getUserId()).get();
updateUser.setUserFullname(user.getUserFullname());
updateUser.setUserAddress(user.getUserAddress());
updateUser.setUserPhone(user.getUserPhone());
updateUser.setUserBankcard(user.getUserBankcard());
userRepository.save(updateUser);
}
//查找所有用户信息
public List<User> findAllUsers(){
return userRepository.findAll();
}
//通过id查找
public User findUserById(Long userId){
return userRepository.findById(userId).get();
}
//通过用户id删除
public void deleteUserById(Long userId){
userRepository.deleteById(userId);
}
//查询用户对应的订单数量,有订单号的用户不允许删除
public int getUserOrderAmount(Long userId){
List<Order> order = orderRepository.findByUserId(userId);
if(order==null){
return 0;
}
else {
return order.size();
}
}
}
3.2.4用户控制层实现
@Controller
public class UserController {
@Autowired
private UserService userService;
@Autowired
private OrderService orderService;
@GetMapping("/login")
public String login(Principal principal){
if(principal == null){
return "login/login";
}
return "redirect:/";
}
//用户注册接口
@GetMapping("/registration")
public String registration(Model model){
User user =new User();
model.addAttribute("user",user);
return "login/registration";
}
//用户注册接口
@PostMapping("/registration")
//@valid用于验证注解是否符合要求,直接加在变量user之前,
// 在变量中添加验证信息的要求,当不符合要求时就会在方法中返回message的错误提示信息。
public String createUser(@Valid User user, BindingResult bindingResult, Model model){
User newUser = userService.findByUserName(user.getUserName());
if(newUser != null){
bindingResult.rejectValue("userName","error.user","用户已经存在");
}
if(!bindingResult.hasErrors()){
userService.registerUser(user);
model.addAttribute("successMessage","用户注册成功");
model.addAttribute("user",new User());
}
return "login/registration";
}
//用户创建
@PostMapping("/users")
@Secured("ROLE_ADMIN")
public String createUser(@RequestBody User user, Model model){
if(user.getUserId()!=0){
model.addAttribute("message","用户信息不存在");
}else if(userService.findByUserName(user.getUserName())!= null){
model.addAttribute("messgae","用户名存在");
}else{
userService.registerUser(user);
model.addAttribute("message","用户创建成功");
}
return "edit/editUser";
}
//获取当前登录用户信息
@GetMapping("/profile")
public String getCurrentUser(Principal principal,Model model){
if(principal == null){
return "redirect:/";
}
User user = userService.findByUserName(principal.getName());
model.addAttribute("user",user);
return "edit/profile";
}
//更新用户信息
@PostMapping("/profile")
public String updateUser(@ModelAttribute User user,BindingResult bindingResult,Model model,Principal principal){
User userExists= userService.findByUserName(user.getUserName());
if(userExists != null&& !Objects.equals(userExists.getUserName(),principal.getName())){
bindingResult.rejectValue("userName","error.user","用户名重复");
}
if(!bindingResult.hasErrors()){
userService.updateUser(user);
model.addAttribute("successMessage","用户信息更新成功");
}
return getCurrentUser(principal,model);
}
//获取所有用户信息查询接口
@GetMapping("/users")
@Secured("ROLE_ADMIN")
public String getUsers(Model model){
List<User> users = userService.findAllUsers();
model.addAttribute("users",users);
return "edit/showAllUsers";
}
//添加用户
@GetMapping("/users/add")
@Secured("ROLE_ADMIN")
public String addUserPage(Model model){
User user = new User();
model.addAttribute("user",user);
return "edit/addUser";
}
//添加用户
@PostMapping("/users/add")
@Secured("ROLE_ADMIN")
public String addUser(@ModelAttribute User user, Model model, BindingResult bindingResult){
User userExists = userService.findByUserName(user.getUserName());
if(userExists!= null){
bindingResult.rejectValue("userName","error.user","用户已存在");
}
if(!bindingResult.hasErrors()){
User newUser =userService.registerUser(user);
model.addAttribute("successMessage","创建用户成功,用户Id:"+newUser.getUserId());
model.addAttribute("user",new User());
}
return "edit/addUser";
}
//通过id编辑用户
@GetMapping("/users/edit/{userId}")
@Secured ("ROLE_ADMIN")
public String editUserPage(@PathVariable Long userId, Model model){
User user = userService.findUserById(userId);
model.addAttribute("user", user);
System.out.println(user);
return "edit/editUser";
}
@PostMapping("/users/edit")
@Secured ("ROLE_ADMIN")
public String editUser(@ModelAttribute User user, Model model) {
userService.updateUser(user);
model.addAttribute("successMessage","用户更新"+user.getUserId());
return editUserPage(user.getUserId(), model);
}
//通过id删除指定用户
@GetMapping("/users/delete/{userId}")
@Secured ("ROLE_ADMIN")
public String deleteUser(@PathVariable Long userId, Model model){
int userOrderAmount = userService.getUserOrderAmount(userId);
if (userOrderAmount > 0) {
model.addAttribute("Message", "该用户名下有"+userOrderAmount+"条订单,不能删除");
}
else{
// userService.deleteUserById(userId);
model.addAttribute("Message", "用户编号"+userId+"删除成功");
}
return getUsers(model);
}
}
3.3前端设计及编码
3.3.1用户注册registration.html
<body>
<div heigth="auto" th:replace="fragments/header :: navbar"></div>
<div class="container p-5">
<h3 class="text-center ">欢迎注册在线书店系统</h3>
<div class="row justify-content-center">
<div class="col-4">
<div class="alert alert-success" th:if="${successMessage}" th:utext="${successMessage}"></div>
<form class="register-form" name="form" role="form" th:action="@{/registration}" th:object="${user}" method="post">
<div class="form-group">
<label class="form-control-label" for="login">用户名:</label>
<input type="text" class="form-control" id="login" name="login"
th:field="*{userName}" required
minlength="1" maxlength="50"
pattern="^[_'.@A-Za-z0-9-]*$">
<div th:if="${#fields.hasErrors('userName')}">
<small class="form-text text-danger" th:errors="*{userName}"></small>
</div>
</div>
<div class="form-group" >
<label class="form-control-label" for="password">密    码:</label>
<input type="password" class="form-control" id="password" name="password"
th:field="*{userPassword}" minlength="4" max="50" required>
<div th:if="${#fields.hasErrors('userPassword')}">
<small class="form-text text-danger" th:errors="*{userPassword}"></small>
</div>
</div>
<div class="pt-2" >
<a class="btn btn-primary" th:href="@{/}">返回首页</a>
<button class="btn btn-primary" type="submit">用户注册</button>
</div>
</form>
</div>
</div>
</div>
</body>
3.3.2用户登录login.html
<body>
<div th:replace="fragments/header :: navbar"></div>
<div class="container-fluid p-5">
<h3 class="text-center ">欢迎使用在线书店系统</h3>
<div class="row justify-content-center">
<div class="col-4">
<div class="alert alert-danger" th:if="${param.error}" >
<strong>无效用户名和密码</strong>
</div>
<form class="form" role="form" th:action="@{/login}" method="post">
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" class="form-control" name="username"
id="username" placeholder="用户名" required>
</div>
<div class="form-group">
<label for="password">密    码:</label>
<input type="password" class="form-control" name="password"
id="password" placeholder="密码" required>
</div>
<div class="col-12 text-end p-2">
<button type="submit" class="btn btn-primary">登录</button>
<a class="btn btn-primary" th:href="@{/registration}">注册</a>
</div>
</form>
</div>
<div class="row justify-content-center">
<div class="col-4">
<div class="alert alert-warning">
<span>还未注册用户吗?请先注册:</span>
</div>
</div>
</div>
</div>
</div>
</body>
3.3.3用户个人信息修改editUser.html
<body>
<div th:replace="fragments/header :: navbar"></div>
<div class="container pt-5">
<div class="row">
<div class="container">
<h3 class="text-center">用户个人信息</h3>
<div class="row d-flex justify-content-center">
<div th:fragment="userForm" class="col-md-4">
<div class="alert alert-success" th:if="${successMessage}" th:utext="${successMessage}"></div>
<form name="userForm" role="form" method="post" th:object="${user}" th:action="@{/users/edit}">
<div class="form-group">
<input type="hidden" class="form-control" id="id" name="id" th:field="*{userId}"/>
</div>
<div class="form-group">
<label class="form-control-label" for="login">用户登录名 </label>
<input type="text" class="form-control" id="login" name="login" th:field="*{userName}" readonly/>
</div>
<div class="form-group">
<label class="form-control-label" for="userFullname">用户全名</label>
<input type="text" class="form-control" id="userFullname" name="userFullname" th:field="*{userFullname}" readonly/>
</div>
<div class="form-group">
<label class="form-control-label" for="userPhone">用户电话</label>
<input type="text" class="form-control" id="userPhone" name="userPhone" th:field="*{userPhone}" required
maxlength="11" pattern="^[0-9]*$" />
<div th:if="${#fields.hasErrors('userPhone')}">
<small class="form-text text-danger" th:errors="*{userPhone}" ></small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="userAddress">用户地址</label>
<input type="text" class="form-control" id="userAddress" name="userAddress" th:field="*{userAddress}" required
maxlength="120" pattern="^[\u4e00-\u9fa5_a-zA-z-0-9]*$" />
<div th:if="${#fields.hasErrors('userAddress')}">
<small class="form-text text-danger" th:errors="*{userAddress}" ></small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="userBankcard">用户银行卡号</label>
<input type="text" class="form-control" id="userBankcard" name="userBankcard" th:field="*{userBankcard}" readonly/>
</div>
<div class="col-12 text-right">
<a type="button" class="btn btn-secondary" th:href="@{/users}">返回</a>
<button type="submit" class="btn btn-primary">信息更新</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
3.3.4用户管理showAllUsers.html
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.2/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js" integrity="sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js" integrity="sha384-ep+dxp/oz2RKF89ALMPGc7Z89QFa32C8Uv1A3TcEK8sMzXVysblLA3+eJWTzPJzT" crossorigin="anonymous"></script>
</head>
<body>
<div th:replace="fragments/header:: navbar"></div>
<div class="container pt-5">
<h3 class="text-center">用户信息汇总</h3>
<div class="row"> </div>
<br/>
<div class="col-6">
<div class="alert alert-danger" th:if="${Message}" th:utext="${Message}"></div>
</div>
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>用户编号</th>
<th>登录名称</th>
<th>用户全名</th>
<th>用户电话</th>
<th>用户地址</th>
<th>银行卡号</th>
<th>管理操作</th>
</tr>
</thead>
<tbody>
<tr th:each="user:${users}">
<td>[[${user.userId}]]</td>
<td>[[${user.userName}]]</td>
<td>[[${user.userFullname}]]</td>
<td>[[${user.userPhone}]]</td>
<td>[[${user.userAddress}]]</td>
<td>[[${user.userBankcard}]]</td>
<td class="text-start">
<div class="btn-group flex-btn-group-container">
<a th:href="@{'/users/edit/{userId}'(userId=${user.userId})}"
class="btn btn-info btn-sm">
<span class="bi bi-eye"></span>
<span class="d-none d-md-inline">编辑</span>
</a>
<a th:href="@{'/users/delete/{userId}'(userId=
${user.userId})}"
class="btn btn-danger btn-sm">
<span class="bi bi-x"></span>
<span class="d-none d-md-inline">删除</span>
</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-10 text-end">
<a class="btn btn-primary" th:href="@{users/add}">新增用户</a>
<a class="btn btn-primary" th:href="@{/}">返回首页</a>
</div>
</body>
</html>
3.3.5创建用户addUser.html
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<head th:replace="fragments/header :: head"></head>
<body>
<div th:replace="fragments/header :: navbar"></div>
<div class="container pt-5">
<h3 class="text-center">新增用户</h3>
<div class="row justify-content-center">
<div class="col-md-4">
<div class="alert alert-success" th:if="${successMessage}"
th:utext="${successMessage}">
</div>
<form name="userForm" role="form" method="post" th:object=
"${user}" th:action="@{/users/add}">
<div class="form-group">
<input type="hidden" class="form-control" id="id"
name="id" th:field="*{userId}"/>
</div>
<div class="form-group">
<label class="form-control-label" for="login">登录名称</label>
<input type="text" class="form-control" id="login"
name="login" th:field="*{userName}" required
maxlength="50" pattern="^[_'.@A-Za-z0-9-]*$">
<div th:if="${#fields.hasErrors('userName')}">
<small class="form-text text-danger" th:errors="*{userName}">
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="userFullname">用户全名</label>
<input type="text" class="form-control" id="userFullname"
th:field="*{userFullname}" name="userFullname" required
maxlength="50" pattern="^[\u4e00-\u9fa5]{0,}*S">
<div th:if="${#fields.hasErrors('userFullname')}">
<small class="form-text text-danger" th:errors="*{userFullname}">
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="password">用户密码
</label>
<input type="password" class="form-control" id="password"
name="password" th:field="*{userPassword}" maxlength=50>
<div th:if="${#fields.hasErrors('userPassword')}">
<small class="form-text text-danger" th:errors="*{userPassword}">
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="userPhone">用户电话</label>
<input type="text" class="form-control" id="userPhone"
th:field="*{userPhone}" name="userPhone" required
maxlength="11" pattern="^[0-9]*$">
<div th:if="${#fields.hasErrors('userPhone')}">
<small class="form-text text-danger" th:errors="*{userPhone}"></small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="userAddress">用户地址</label>
<input type="text" class="form-control" id="userAddress"
th:field="*{userAddress}" name="userAddress" required
maxlength="120" pattern= "^[\u4e00-lu9fa5_a-zA-Z0-9]*$">
<div th:if="${#fields.hasErrors('userAddress')}">
<small class="form-text text-danger" th:errors="*{userAddress}">
</small>
</div>
</div>
<div class="form-group">
<label class="form-control-label" for="userBankcard">银行卡号</label>
<input type="text" class="form-control" id="userBankcard" th:field="*{userBankcard}"
name="userBankcard" required maxlength="80" pattern="^[0-9]*$">
<div th:if="${#fields.hasErrors('userBankcard')}">
<small class="form-text text-danger" th:errors="*{userBankcard}">
</small>
</div>
</div>
<div class = "col-12 text-right">
<a type="button" class="btn btn-secondary" th:href="@{/users}">返回</a>
<button type="submit" class="btn btn-primary">新建</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
3.3.6删除用户
<!--已包含在showAllUsers文件中-->
<a th:href="@{'/users/delete/{userId}'(userId=
${user.userId})}"
class="btn btn-danger btn-sm">
<span class="bi bi-x"></span>
<span class="d-none d-md-inline">删除</span>
</a>
四、mybatis与mybatis-plus实现以及它们之间的区别。
MyBatis 是一个基于 Java 的持久层框架,它通过 XML 或注解的方式将对象与 SQL 语句进行映射,提供了灵活的 SQL 查询和结果映射功能。而 MyBatis-Plus 是 MyBatis 的增强工具包,提供了更多便捷的功能和增强的特性,使得开发人员能够更高效地进行数据库操作。
下面是它们的实现方式和主要区别:
MyBatis 实现:
-
XML 文件配置: 在 MyBatis 中,通常需要编写 XML 文件来配置 SQL 映射关系,定义 SQL 语句、参数映射以及结果集映射等内容。
-
SQL 控制: 开发人员需要手动编写 SQL 语句,并在 XML 文件中进行配置,包括 SQL 查询、更新、删除等。
-
基本功能: MyBatis 提供了基本的数据库操作功能,包括 SQL 查询、参数绑定、结果集映射等。
MyBatis-Plus 实现:
-
基于 MyBatis: MyBatis-Plus 是在 MyBatis 的基础上进行了功能增强和扩展,可以作为 MyBatis 的增强工具包来使用。
-
注解支持: MyBatis-Plus 提供了注解方式的配置,简化了 XML 配置文件的编写,提供了更便捷的开发方式。
-
CRUD 方法封装: MyBatis-Plus 封装了常见的 CRUD(Create, Retrieve, Update, Delete)操作方法,使得开发人员不需要手动编写 SQL 语句,可以通过简单的方法调用来完成数据库操作。
-
分页插件: MyBatis-Plus 提供了强大的分页插件,可以方便地进行分页查询操作。
区别和优势:
-
开发效率: MyBatis-Plus 在 MyBatis 的基础上提供了更多便捷的功能和方法封装,可以大大提高开发效率,减少重复代码的编写。
-
注解支持: MyBatis-Plus 提供了更多的注解支持,简化了 XML 配置文件的编写,使得开发更加便捷。
-
CRUD 方法封装: MyBatis-Plus 封装了通用的 CRUD 操作方法,可以直接调用,省去了手动编写 SQL 语句的过程。
总的来说,MyBatis-Plus 是 MyBatis 的增强工具包,提供了更多便捷的功能和方法封装,可以大大提高开发效率,特别适合对 CRUD 操作频繁的业务场景。如果您需要快速、高效地进行数据库操作,并且喜欢注解方式的配置,MyBatis-Plus 是一个很好的选择。
五、Web应用项目开发中最常遇见的问题,以及解决方法
性能问题: 应用响应时间慢、负载高等。解决方法包括:
- 优化数据库查询:使用索引、合理设计表结构。
- 使用缓存:缓存常用数据、页面片段等。
- 优化代码:减少循环嵌套、避免重复计算等。
安全问题: 如跨站脚本攻击(XSS)、跨站请求伪造(CSRF)等。解决方法包括:
- 输入验证和过滤:对用户输入进行验证,并过滤可能的恶意代码。
- 使用安全框架:如Spring Security,提供身份认证和授权功能。
- 防御机制:设置合适的响应头、使用验证码等。
跨浏览器兼容性问题: 不同浏览器对CSS和JavaScript的支持不同,导致页面在不同浏览器上显示效果不一致。解决方法包括:
- 使用CSS Reset:重置浏览器默认样式,保证页面在不同浏览器上的一致性。
- 使用CSS前缀:为CSS属性添加浏览器厂商前缀,以支持不同浏览器。
- 使用Polyfills和垫片库:填补浏览器兼容性差异,提供一致的API和功能支持。
部署和环境问题: 在部署到生产环境时遇到配置错误、依赖缺失等问题。解决方法包括:
- 自动化部署:使用工具如Docker、Kubernetes等进行自动化部署。
- 环境管理:使用配置管理工具(如Ansible)管理环境配置。
- 错误日志监控:使用监控工具(如ELK Stack)实时监控应用错误日志。
代码质量问题: 代码冗余、可维护性差、可扩展性差等。解决方法包括:
- 代码重构:去除冗余代码、提取公共方法等。
- 代码规范和代码审查:遵循编码规范,进行代码审查和团队合作。
- 单元测试和集成测试:编写测试用例,保证代码质量和稳定性。
以上是常见的问题及其解决方法,但具体问题还可能因项目需求、技术栈和开发环境而有所不同。在开发过程中,及时调试、排查问题,并参考相关文档和社区讨论,将有助于更快地解决问题。同时,团队协作和经验积累也是解决问题的重要因素。