Spring Boot小项目2
前端表单和后端的连接
前端
首先我们在index.html里面找到类似这样的form
<form action="/user/login" method="post">
<input type="text" name="username" placeholder="请输入用户名">
<input type="password" name="password" placeholder="请输入密码">
<button type="submit">登录</button>
</form>
这是我用ai的 因为我找到index.html根本没有这个哈哈哈哈哈哈 够了
然后看到这个<form action="/user/login" method="post">
因为我们用的thymeleaf文件依赖所以要把这个改一下
<form th:action="@{/user/login}" method="post">
里面的这个/user/login是我们自己定义的
网址路径(URL Path)
一个用于“接收数据”的地址(专业术语叫 API 端点或 Endpoint)。
th:action="@{/user/login}" -- 这个属性明确地告诉浏览器:“当用户点击提交按钮后,请把表单里所有的数据,发送到服务器上的 /user/login 这个路径去。”
name="username" 和 name="password":
这两个 name 属性至关重要!当表单被提交时,浏览器会收集这些输入框的数据,并生成类似这样的内容:username=用户输入的值&password=用户输入的值。
Spring 框架看到请求参数的名字 (username, password) 和你Controller方法中的参数名 (String username, String password) 一模一样,就会自动把前端的值赋给后端的参数。这个功能叫“参数绑定”,是Spring的一大便利特性。
我们在index.html文件里面改好这个之后
我们就去Controller包里创建一个LoginController类
Controller包 - LoginController.java
这个时候 你就要问了 Controller包是什么 LoginController又是什么
Controller - 控制器
作用:
在一个典型的 Web 应用程序(比如一个网站)中,控制器扮演着“交通警察”或“调度员”的角色。它的核心职责是:
接收用户的请求(比如,用户在浏览器地址栏输入一个网址,或者点击了一个提交按钮)。
处理请求(比如,检查你提交的用户名和密码是否正确)。
返回响应(比如,告诉你“登录成功,欢迎回来!”或者“密码错误,请重试”)。
我们把所有充当控制器角色的类都放在 Controller 包(或类似的如 web, api 包)下
创建一个 LoginController 类,就是为了专门处理所有和“登录”相关的用户请求。
后端
现在我们回来看
在LoginController里我们
创建一个公共的LoginController类,
然后在里面申明一个login方法
用于用户传入用户名和密码(String name,String password)
为了接收用户提交过来的这两个数据。Spring 框架会自动把表单里的数据抓取出来,并传递给你方法的参数。你之后就可以在方法内部使用这些数据了
同时我们要在方法上面引用两个注释
@RequestMapping("/user/login")
建立一个映射关系,告诉 Spring 框架:
“嘿!如果有一个来自浏览器的请求,它的(URL Path) 长这样,那就由我下面这个方法来处理它!”
@ResponseBody
//一个专门处理所有和“登录”相关的用户请求。
public class LoginController {
@RequestMapping("/user/login")
public String login(@RequestParam ("username")String username,
@RequestParam ("password") String password,
Model model){ //用于向视图传递数据(如错误信息)
if(!StringUtil.isNullOrEmpty(username) && "123456".equals(password)){
return "dashboard"; //但其实我没有dashboard这个html
}else{
model.addAttribute("msg","用户名或密码错误");
return "index";
}
}
}
@ResponseBody - 直接写入响应体
方法返回一个对象(String, List, 自定义对象等),Spring 会直接将这个对象本身写入到 HTTP 响应体(Response Body)中。
告诉 Spring,“不要把这个方法的返回值当成视图文件名去查找页面,而是直接把它作为HTTP响应的内容本身输出给客户端”。
这里的return我们也可以跳转到其他的页面,成功页或者登录失败
返回类型 (String):
这个方法需要返回一个字符串,这个字符串通常代表一个视图(View)的名字,也就是接下来要展示给用户的网页。
Spring 会根据这个返回的字符串,去找到对应的网页文件(比如 login-success.html 或 login-fail.html)并返回给用户的浏览器显示。
例如:return "login-success"; 或 return "homepage";
回顾整个流程
- 用户首先访问首页
- 在浏览器打开http://localhost:8080/index
- 服务器返回 index.html 页面。
- 用户填写表单
- 在表单里输入用户名和密码
- 用户提交
- 浏览器行动:
- 浏览器根据表单的action请求,创建一个新的HTTP POST请求
- 将请求发送到http://localhost:8080/user/login,并且将表单数据放在请求内
- Spring接收到了目标是/usr/login的post请求
- 映射匹配:
- Spring 找到标注了 @RequestMapping("/user/login") 的 login 方法。
- 执行:
- Spring将请求转给login方法,并自动将请求体类的username和password值提取出来,作为参数传入方法中
- 处理业务:你的方法执行登录逻辑(验证账号密码)
- 返回响应:
- 方法返回一个结果 - 跳转成功或者失败页面
- 用户看到结果:浏览器收到响应,加载新的页面。
简化@RequestMapping 和 @ResponseBody
组合注解:@RestController = @RequestMapping 和 @ResponseBody
整个类中所有方法的返回值都会被视为响应体内容,而不是视图名称。
只要在类上面引用这个注解,就不用在方法上面写@ResponseBody了
处理用户名和密码为空或者错误提示
//如果msg的值为空则不显示消息
<p> style="color : red" th:text="${msg}" th:if=""${not #strings.isEmpty(msg)}"</p>
然后我们在MyMvcConfig类里面加上
registry.addViewController("/main.html").setViewName("dashboard");
/main.html - URL Path
再把return "dashboard";
改成return "redirect:/main.html";
redirect再直接询问
@RequestMapping("/user/login")
public String login(@RequestParam ("username")String username,
@RequestParam ("password") String password,
Model model){ //用于向视图传递数据(如错误信息)
if(!StringUtil.isNullOrEmpty(username) && "123456".equals(password)){
return "redirect:/main.html";
}else{
model.addAttribute("msg","用户名或密码错误");
return "index";
}
}
}
拦截
现在还有一个问题
就是
这样我直接访问/main.html也能进来这个页面 根本不用输入用户名和密码
所以我们要设置一个拦截器
拦截器是Spring MVC框架中的一种机制,允许在请求处理的前后执行自定义逻辑
类似于过滤器(Filter),但更专注于处理程序(Handler)的拦截
//实现登录拦截
public class LoginHandlerInterceptor implements HandlerInterceptor { //HandlerInterceptor程序拦截器
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//登录成功之后,应该有用户的session
request.getSession().getAttribute("loginUser");
if(request.getSession().getAttribute("loginUser")==null){ //没有登录
request.setAttribute("msg","没有权限请先登录");
request.getRequestDispatcher("/index.html").forward(request,response);
return false; //不放行
}else {
return true;
}
}
}
我们来分析这段代码
public class LoginHandlerInterceptor implements HandlerInterceptor { //HandlerInterceptor程序拦截器
// 实现HandlerInterceptor接口,表示这是一个处理程序拦截器
HandlerInterceptor接口
Spring MVC提供的拦截器接口,包含三个方法:
preHandle(): 在处理程序执行前调用
postHandle(): 在处理程序执行后、视图渲染前调用
afterCompletion(): 在整个请求完成后调用
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
这个preHandle相当于一个安检方法
“这个方法是在进行网页跳转处理程序执行前,先进行检查的方法”。它检查的不是原始的“用户名密码”,而是之前登录成功后发放的“通行证”(Session)
HttpServletRequest request - 就是用户请求
包含了用户所有信息的包裹
不是用户名和密码
session-身份证一样的东西,可能有之前登录时发放的通行证loginUser
用户想去哪里的地址(请求的URL,比如 /user/shopping)
用户身上带的东西(请求参数)
等等
用户的用户名和密码就在这个“包裹”的某个口袋里,但安检不直接看那个,它只看你之前登录成功后发放的“通行证”(Session)。
那安检完之后就是回应了
HttpServletResponse response - 给用户的回应
直接给用户一个答复
告诉用户“不行,请去那边”(跳转到登录页 forward 或 sendRedirect)
直接告诉用户一个错误信息
Object handler - 用户最终想见的人
可能是 UserController 里的某个方法(比如处理购物的方法)
可能是 ProductController 里的某个方法(比如处理查看商品的方法)
这三个参数是Spring框架强制规定的
然后大括号里面的所有代码就是preHandle拿到三个参数后执行的步骤
request.getSession().getAttribute("loginUser");
通过 request.getSession() 拿到你的档案袋,查看里面的历史记录(getAttribute("loginUser"))
getAttribute-读取登记信息(loginUser)
request.setAttribute("msg","没有权限请先登录");
接下来要带用户去登录处(/login.html)。它需要把为什么带用户来这的原因告诉登录处的同事(login.html页面),这样登录页面就能显示出“没有权限请先登录”这句话。这个信息是在服务器内部传递的,用户看不见这个过程。
request.getRequestDispatcher("/index.html").forward(request,response);
response - 真正用来组织并发送回应给用户的
整个 forward 操作最终需要调用response 对象来完成向用户浏览器发送指令的过程
虽然代码里没直接写,但 forward 方法内部在帮你使用 response
然后我们要在MyMvcConfig里面添加
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**").excludePathPatterns("/index.html","/mian.html","/","/user/login","/css/*","/js/*","/images/*","/webjars/**");
WebMvcConfigurer.super.addInterceptors(registry);
}
// /*全部文件 /**全部子文件```
在dashboard文件里面我们要那某个地方修改成
[[${session.loginUser}]]
显示自己登录的用户名
$ 就是取表达式的
# 显示员工列表
## 后端-查找所有员工
在Contrller下面创建一个EmployeeController类
//标记这个类是一个控制器(Controller)。
@Controller
public class EmployeeController { //这个类专门负责处理与员工(Employee)相关的所有 Web 请求
//使用 @Autowired 注解自动注入 EmployeeDao 依赖
@Autowired
EmployeeDao employeeDao;
//将这个方法映射到特定的 URL 路径
//当用户访问 http://你的域名/emps 时,Spring 会调用这个方法来处理请求
@RequestMapping("/emps")
public String list(Model model) { //参数 Model model 是一个模型对象,用于*向视图(页面)传递数据*
Collection<Employee> employees = employeeDao.getAll();
//将数据添加到模型中,以便在视图中使用
model.addAttribute("emps",employees);
return "list"; //指定要渲染的视图名称
}
}```
```@Autowired
EmployeeDao employeeDao;
EmployeeDao 是一个数据访问对象(Data Access Object),负责与数据库交互,执行CRUD操作。
@Autowired 让 Spring 自动找到合适的 EmployeeDao 实现并注入到这个字段中,*无需手动创建实例*。
这体现了依赖注入(Dependency Injection) 原则,使代码更松耦合、易于测试。
model.addAttribute("emps",employees);
将员工集合以键值对形式添加到模型。
键名是 "emps",值是 employees 集合。
在视图中可以通过 ${emps} 访问这个员工列表。
Collection<Employee> employees = employeeDao.getAll();
Collection - 表示一个集合容器
employees - 给这个装满员工的盒子起的变量名
= employeeDao.getAll() - 把右边方法返回的“员工盒子”,赋值给左边名为 employees 的“员工盒子”;getAll() 方法返回的也必须是一个 Collection
<> 就像给容器贴上的标签,说明了里面装的是什么
在前端展示员工的信息
提取公共页面
通常应用里面都有一个侧边栏(sidebar) 然后我们就把它抽取出来,比如你的侧边栏是在dashboard.html拿的
... th:fragment="sidebar" >
这样这个侧边栏就会变成一个组件
然后插入到员工列表的前端文件里
模板:
commons-组件页面路径
<div>th:insert="~{dashboard :: sidebar}"</div>如果抽取导航栏topbar也是同样的操作
我们可以在templates里面创建一个commons包,再创建一个commons.html
把侧边栏跟导航栏放在这里
这样的话我们要用这两个组件就要在list.html或者别的地方这样写 - th:replace
<div>th:replace="~{commons/commons :: dashboard}"</div>
高亮 - active
要判断我们点了哪个按钮哪个按钮就高亮
那么我们就要
传递参数 - 直接使用括号传参
模板:
(if) ? (then) : (else)
dashboard.html:
<div>th:replace="~{commons/commons :: sidebar(active='main.html')}"</div>
commons.html:
<a th:class="@{active=='list.html'?'nav-link active':'nav-link'}" th:href="@(/index.html)">
list.html:
<div>th:replace="~{commons/commons :: sidebar(active='list.html')}"</div>
nav-link active - 激活
nav-link - 默认链接
遍历员工信息
<tbody>
<tr th:each="emps:${emps}">
<td th:text="${emps.getId()}"></td>
<td>[[${emps.getId()}]]</td>
<td th:text="${emps.getEmail()}"></td>
<td th:text="${emps.getGende()==0?'女':'男'}"></td>
<td th:text="${emps.department.getDepartmentName()}"></td>
<td th:text="${#dates.format(emp.getBrith(),'yyy-MM-dd HH:mm:ss')}"></td>
</tr>
</tbody>
${emps.getGende()==0?'女':'男'}
如果是0就输出女,否则男
${#dates.format(emp.getBrith(),'yyy-MM-dd HH:mm:ss')}
加按钮
每一行
btn - 标签
btn-sm 小标签
btn- primary 主样式
<button class= "btn btn-sm btn-primary">编辑</button>
<button class= "btn btn-sm btn-danger">删除</button>
//按钮 小按钮 按钮的颜色
添加员工实现
前端
在页面上设置超链接
1. 按钮提交添加
2. 跳转到添加页面
3. 添加员工成功返回首页
<h2><a class="btn btn-sm btn-success" th:href="@{/emp}">
跳转链接到/emp实现get()请求
添加了一个add.html之后,改一下嵌入一个form表单
下拉框 - 遍历部门
<select class="from-control" name="department.id">
<option th:each="${dept:departments}" th:text="${dept.getDepartmentName}" th:value="${dept.getId()}"></option>
</select>
//取出来之后每个值叫dept ,然后把取出来的值显示出来
//给Option赋值
//我们在controller接收的是一个Employee,所有我们需要提交的十一属性
在add.html的form那里要这样写
<form th:action="@{/emp}" method="post">
后端EmployeeController那里也有一个PostMapping
后端
在Controller包下面的EmployeeController类里面添加方法
@Autowired
DepartmentDao departmentDao;
@GetMapping("/emp")
public String toAddpage(Model model){
//查出所有部门的信息
Collection<Department> departments = departmentDao.getDepartments();
model.addAttribute("departments",department);
return "emp/add";
//在templates加一个add.html页面,直接复制list.html再改就行
@PostMapping("/emp") //这里/emp就是填写添加员工的页面
public String addEmp(Employee employee) {
//添加的操作 forward
employeeDao.save(employee); //调用底层业务员工方法保存员工信息
return "redirect:emps"; //走到上面那个GetMapping请求然后刷新列表
//在templates加一个add.html页面,直接复制list.html再改就行
}
}
@GetMapping - 获取资源(查询、显示页面)
简化HTTP GET 请求映射的注解
简写:
//如下
@RequestMapping(value = "/emps", method = RequestMethod.GET)
public String list(Model model) {
// ...
}
使用@GetMapping
@GetMapping("/emps")
public String list(Model model) {
// ...
}
@PostMapping - 创建资源(提交表单、添加数据)
@PutMapping - 更新资源(修改现有数据

浙公网安备 33010602011771号