SpringBoot开发一个简单的网站
2022-10-24 15:56:58
169
{{single.collect_count}}

project:springboot-02!!!

一、模拟一个数据库

pojo.Department

@Data@AllArgsConstructor@NoArgsConstructorpublic class Department {private Integer id;private String departmentName;}

pojo.Employee

@Data@NoArgsConstructor@AllArgsConstructorpublic class Employee {private Integer id;private String lastName;private String email;private Integer gender;//0女1男private Department department;private Date birth;}

dao.DepartmentDao

@Repositorypublic class DepartmentDao {//模拟数据库中的数据private static Map<Integer, Department> departments = null;static {//Map中的key代表数据库的索引,value代表索引对应的这一行记录departments = new HashMap<Integer, Department>();//创建一个部门数据表departments.put(101, new Department(101, "教学部"));departments.put(102, new Department(102, "市场部"));departments.put(103, new Department(103, "教研部"));departments.put(104, new Department(104, "运营部"));departments.put(105, new Department(105, "后勤部"));}//获取所有部门信息public Collection<Department> getDepartments(){return departments.values();}//通过id得到部门public Department getDepartmentById(Integer id){return departments.get(id);}}

dao.EmployeeDao

@Repositorypublic class EmployeeDao {//模拟数据库中的数据private static Map<Integer, Employee> employees = null;@Autowiredprivate DepartmentDao departmentDao;static {//Map中的key代表数据库的索引,value代表索引对应的这一行记录employees = new HashMap<Integer, Employee>();employees.put(1001, new Employee(1001, "AA", "392851349@qq.com", 0, new Department(101, "教学部"), new Date()));employees.put(1002, new Employee(1002, "BB", "378985149@qq.com", 0, new Department(102, "市场部"), new Date()));employees.put(1003, new Employee(1003, "CC", "848695349@qq.com", 1, new Department(103, "教研部"), new Date()));employees.put(1004, new Employee(1004, "DD", "648695349@qq.com", 1, new Department(104, "运营部"), new Date()));employees.put(1005, new Employee(1005, "EE", "248695349@qq.com", 1, new Department(105, "后勤部"), new Date()));}//主键自增private static Integer initId = 1006;//增加一个员工public void addEmployee(Employee employee){if(employee.getId()==null){employee.setId(initId++);}employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));employees.put(employee.getId(), employee);}//查询全部员工public Collection<Employee> getAll(){return employees.values();}//通过id查询员工public Employee getEmployeeById(Integer id){return employees.get(id);}//通过id删除员工public void delete(Integer id){employees.remove(id);}}

@Repository注解 

@repository跟@Service,@Compent,@Controller这4种注解是没什么本质区别,都是声明作用,取不同的名字只是为了更好区分各自的功能.

@Repository

@Repository

  • 对DepartmentDao注解上@Repository后,   
  • @Autowire
  • private DepartmentDao departmentDao;
  • 就可以这样自动注入了,而不需要new对象

二、导入静态资源

 具体资源在java后端开发文件的狂神springboot静态资源目录

  • 注意这里面的html放在templates下,css、js、图片放在static下

 三、首页


controller层:

//首页@Controllerpublic class IndexController {@RequestMapping({"/", "/index", "/index.html"})//不管是访问"/", "/index", "/index.html"中的哪一个,都可以跳转到index.html页面public String index(){return "index";}}
  • 在这里终于搞明白了return的作用,也就是说当请求localhost:8080/index的时候,视图控制器跳转到resources/templates/index.html。
  • return的字符串其实就是templates下的文件名

结果:

  •  但是这里的index首页中一些css样式和图片没有加进来,下一步就要把html文件中添加css、img
  • 通过thymeleaf模板

扩展MVC

除了通过上述方式跳转到主页index.html以外,还可以通过自己定义的方式去扩展mvc

config.MyMvcConfig类:

@Configuration//@EnableWebMvcpublic class MyMvcConfig implements WebMvcConfigurer{@Overridepublic void addViewControllers(ViewControllerRegistry registry){registry.addViewController("/").setViewName("index");registry.addViewController("/index").setViewName("index");registry.addViewController("/index.html").setViewName("index");}}
  • @Configuration表示是一个配置类
  • 不能加上@EnableWebMvc,加上后表示springboot 的所有默认配置都失效了,但是我们只想更改部分默认配置
  • registry.addViewController("/").setViewName("index");//访问根目录时,跳转到index.html文件

        但是这里的index首页中一些css样式和图片没有加载进来,下一步就要把html文件中添加css、img。

        通过thymeleaf模板引擎来在html加载静态资源

1、在html中添加thymeleaf命名空间

<html lang="en" xmlns:th="http://www.thymeleaf.org">

2、 更改html中的超链接:

<link href="asserts/css/bootstrap.min.css" rel="stylesheet">
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

3、......

        在application.properties中关闭模板引擎的缓存,否则更改的html会因为缓存而无效

spring.thymeleaf.cache=false

四、首页的国际化

1、首先在File-setting-Editor-File Encodings中确保都是utf8,否则会乱码

2、在resources下新建一个i18n文件夹(全称:internationalization,i和n之间有18个字母)

      新建三个名为:login.properties、login_en_US.properties、login_zh_CN.properties的配置文件,springboot会根据文件名自动识别其功能,并把它们自动合并在Resource Bundle 'login'

 login.properties(默认)

login.tip=请登录login.password=密码login.remember=记住我login.username=用户名login.btn=登录

login_en_US.properties(英文)

login.tip=Please sign inlogin.password=passwordlogin.remember=remember melogin.username=user namelogin.btn=sign in

login_zh_CN.properties(中文)

login.tip=请登录login.password=密码login.remember=记住我login.username=用户名login.btn=登录

3、application.properties中添加配置:

#国际化的配置文件所在地spring.messages.basename=i18n.login

4、修改对应的index.html文件

 ...............省略下面过程

五、首页的登录功能

功能描述:

        首页输入用户名和密码,如果正确,则页面跳转,如果不正确,那么提示密码错误。


首先来看首页提交的表单部分:

  •  form标签的action属性表示表单提交后处理表单的url地址,用thymeleaf改写前这个form是这样的:但是这样只是静态的,无法和服务器交互
    <form class="form-signin" action="dashboard.html">

    注意thymeleaf中url用@{}来表示,改写后表示表单提交后,                                                    将跳转到localhost:8080/user/login请求

  • 要实现登录功能,input标签必须有name属性,这个name属性不仅仅是别名的作用,还作为可与服务器交互数据的HTML元素的服务器端的标示,比如input、select、textarea、和button的name属性都有这个功能。我们可以在服务器端根据其Name通过@RequestParam取得元素提交的值


controller层:

在controller文件夹下新建一个类:

@Controllerpublic class LoginController {@RequestMapping("/user/login")public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model){//获取到提交的表单的username、password后,进行具体的业务(这里是验证用户名密码是否正确业务)if(username!=null && password.equals("123456")){return "dashboard";//登录成功,跳转到dashboard.html页面}else{//显示登陆失败//通过model向页面传递值model.addAttribute("msg","用户名密码错误!");return "index";}}}
  • 这里要结合index.html的表单部分来看
  • form表单提交后,<form class="form-signin" th:action="@{/user/login}">,这个表示会产生一个localhost:8080/user/login的请求,从而这个请求会被上面这个controller层的login方法接收。(action="@{/user/login}和@RequestMapping("/user/login")相互对应)这里你也可以仔细品味一下@RequestMapping,翻译为中文就是请求映射,把一个请求映射到另外一个路径上
  • @RequestParam("username") String username 就表示把name="username"的标签的内容(这里指的是input标签中,我们从网页输入的内容)获取到,并且就是这个String username
  • Model model的作用是向前端页面传递值。
    model.addAttribute("msg","用户名密码错误!");//即向下面这个p标签的msg传递值
  • <p th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>
  • p标签的作用是,如果msg不为空(即msg为用户名密码错误!),就将这个p标签显示出来,否则不显示(用户名密码正确)。
  • 用户名密码错误时:

  •  用户名密码正确时:

  •  但是注意上面这个url:

http://localhost:8080/user/login?username=ZY2002529&password=123456

  • 这个url并不是这个页面的地址:localhost:8080/dashboard.html
  • 而是一个请求(从“?username=ZY2002529&password=123456”这些参数就可以很明显看出来)
  • 因此就要介绍一下请求转发和重定向的区别了!

@RequestMapping注解所在的方法

  1. 如果是return " ****** "; 那么是请求转发
  2. 如果是return " redirect:/ ***** "; 是重定向

总结重定向和请求转发的区别



  • 请求转发:直接调用跳转的页面,让它返回,但是对于浏览器来说,地址栏不变,地址栏仍然是请求


  • 请求重定向:重定向是发一个302的状态码给浏览器,浏览器自己去请求跳转的网页,url会改变,request数据不带到重定向的方法中

 重定向的方式进入dashboard.html页面

  •  上述方式是错误的,会404,找不到dashboard.html,没搞明白为啥!????????

  • 必须在扩展MVC配置类中加入这个才能正确跳转到dashboard.html 

六、登录拦截器 

        登录拦截器的作用就是必须在你登录了以后才可以进入到http://localhost:8080/dashboard,否则你直接输入这个网址也可以进入。


首先需要使用session

@Controllerpublic class LoginController {@RequestMapping("/user/login")public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model, HttpSession session){//获取到提交的表单的username、password后,进行具体的业务(这里是验证用户名密码是否正确业务)if(username!=null && password.equals("123456")){session.setAttribute("loginUser", username);return "redirect:/dashboard";//登录成功,跳转到dashboard.html页面}else{//显示登陆失败//通过model向页面传递值model.addAttribute("msg","用户名密码错误!");return "index";}}}
  • 在login方法参数中加入 HttpSession session参数
  • 当验证密码通过后,给session赋值: session.setAttribute("loginUser", username); 也就是给别名为loginUser的Session赋值为username

什么是session和cookie?

Session:记录一系列状态

        Session与cookie功能效果相同。Session与Cookie的区别在于Session是记录在服务端的,而Cookie是记录在客户端的。

解释session:当访问服务器否个网页的时候,会在服务器端的内存里开辟一块内存,这块内存就叫做session,而这个内存是跟浏览器关联在一起的。这个浏览器指的是浏览器窗口,或者是浏览器的子窗口,意思就是,只允许当前这个session对应的浏览器访问,就算是在同一个机器上新启的浏览器也是无法访问的。而另外一个浏览器也需要记录session的话,就会再开启一个属于自己的session

原理:HTTP协议是非连接性的,取完当前浏览器的内容,然后关闭浏览器后,链接就断开了,而没有任何机制去记录取出后的信息。而当需要访问同一个网站的另外一个页面时(就好比如在第一个页面选择购买的商品后,跳转到第二个页面去进行付款)这个时候取出来的信息,就读不出来了。所以必须要有一种机制让页面知道原来页面的session内容。

问题:如何知道浏览器和这个服务器中的session是一一对应的呢?又如何保证不会去访问其它的session呢?

原理解答:就是当访问一个页面的时候给浏览器创建一个独一无二的号码,也给同时创建的session赋予同样的号码。这样就可以在打开同一个网站的第二个页面时获取到第一个页面中session保留下来的对应信息(理解:当访问第二个页面时将号码同时传递到第二个页面。找到对应的session。)。这个号码也叫sessionID,session的ID号码,session的独一无二号码。
————————————————
版权声明:本文为CSDN博主「广小白」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42217767/article/details/92760353


在config包下新建一个类:LoginHandlerInterceptor

public class LoginHandlerInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//登录成功后,应该会有用户的sessionObject loginUser = request.getSession().getAttribute("loginUser");//获取别名为loginUser的session中存储的内容if(loginUser==null){request.setAttribute("msg", "没有权限,请先登录");//给msg赋值,这个msg是index.html中的参数request.getRequestDispatcher("/index.html").forward(request, response);return false;}else{return true;}}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}}
  • 在SpringMVC 或者SpringBoot中定义一个拦截器是比较非常简单,主要有两种方式:
    • 1、类要实现Spring 的HandlerInterceptor 接口
    • 2、类继承实现了HandlerInterceptor 接口的类,例如 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter
  • HandlerInterceptor:Handler(处理程序)Interceptor(拦截器),即拦截器处理程序
  • HandlerInterceptor的三个方法

    • preHandle:该方法将在请求处理之前进行调用,只有该方法返回true,才会继续执行后续的Interceptor和Controller,当返回值为true 时就会继续调用下一个Interceptor的preHandle 方法,如果已经是最后一个Interceptor的时候就会是调用当前请求的Controller方法;预处理,可以进行编码、安全控制、权限校验等处理;(上面红字的“请求”就是,/user/login请求,即前端的表单提交后发送的一个请求,“请求处理之前”也就是被LoginController的login方法返回页面return处理之前)

    • postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。

    • afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);

  • request.getRequestDispatcher是请求转发的意思,具体可以看下面这个博客,写的很好请求重定向、请求转发、请求包含的特点与区别详解


接下来需要在主配置文件MyMvcConfig中进行配置
 

@Configuration//@EnableWebMvcpublic class MyMvcConfig implements WebMvcConfigurer{//实现WebMvcConfigurer接口的类会被springboot认为是配置类@Overridepublic void addViewControllers(ViewControllerRegistry registry){registry.addViewController("/").setViewName("index");registry.addViewController("/index").setViewName("index");registry.addViewController("/index.html").setViewName("index");registry.addViewController("/dashboard.html").setViewName("dashboard");registry.addViewController("/dashboard").setViewName("dashboard");}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/index", "/", "/user/login", "/css/**", "/img/**", "/js/**");}}
  • 添加一个拦截器,把LoginHandlerInterceptor类的对象传参进去
  • addPathPatterns("/**"):表示拦截所有请求
  • excludePathPatterns("/index", "/", "/user/login", "/css/**", "/img/**", "/js/**"):表示排除以下请求

添加拦截器成功后,如果不登录,直接访问http://localhost:8080/dashboard就会:

登录成功后,会发现请求中多了一个sessionId

 如果你登录后把页面关闭了,再去直接访问http://localhost:8080/dashboard的时候会发现竟然也可以直接打开,是因为session的存在。如果把浏览器所有历史记录包括cookie和session删除,就不能直接打开了。

 七、展示员工列表

 对应的dashboard.html:

<li class="nav-item"><a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">员工管理</a></li>
  • href对应的是点击后跳转的地址连接(其实是一个请求),这个请求被Controller接收

修改为:

<li class="nav-item"><a class="nav-link" th:href="@{/employee}">员工管理</a></li>

对应controller层 

@Controllerpublic class EmployeeController {@AutowiredEmployeeDao employeeDao;@RequestMapping("/employee")public String selectAllEmployees(Model model){Collection<Employee> AllEmployees = employeeDao.getAll();model.addAttribute("emps", AllEmployees);return "/employee/list";}}
  • 点击员工管理,controller接收/employee请求,利用model向前端传递值,返回/employee/list页面

未修改前的/employee/list:

 修改/employee/list.html

<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4"><h2>Section title</h2><div class="table-responsive"><table class="table table-striped table-sm"><thead><!--thead是table head--><tr><th>id</th><th>lastname</th><th>email</th><th>gender</th><th>department</th><th>birth</th></tr></thead><tbody><!--table 部分--><tr th:each="emp:${emps}"><td th:text="${emp.getId()}"></td><td th:text="${emp.getLastName()}"></td><td th:text="${emp.getEmail()}"></td><td th:text="${emp.getGender()}"></td><td th:text="${emp.getDepartment().getDepartmentName()}"></td><td th:text="${emp.getBirth()}"></td></tr></tbody></table></div></main>
  • <tr th:each="emp:${emps}">中的emps是EmployeeController中的model.addAttribute("emps", AllEmployees); each代表对集合emps进行遍历,emp是emps的别名

 上面的页面的问题是1、gender,应该把01改为男女 2、后面应该添加对员工的删除操作

<thead><!--thead是table head--><tr><th>id</th><th>lastname</th><th>email</th><th>gender</th><th>department</th><th>birth</th><th>操作</th></tr></thead><tbody><!--table 部分--><tr th:each="emp:${emps}"><td th:text="${emp.getId()}"></td><td th:text="${emp.getLastName()}"></td><td th:text="${emp.getEmail()}"></td><td th:text="${emp.getGender()==0?'女':'男'}"></td><td th:text="${emp.getDepartment().getDepartmentName()}"></td><td th:text="${emp.getBirth()}"></td><td><button class="btn btn-sm btn-primary">编辑</button><button class="btn btn-sm btn-danger">删除</button></td></tr></tbody>

修改后:

 这一节还有几个小问题我没弄:

  1. 菜单栏点击高亮
  2. 员工birth的Date日期形式转化 
  3. 不同页面公共的部分应该抽取出来,便于后期维护

八、添加员工

在员工表单的顶部设置 添加员工 按钮

<h2><a class="btn btn-sm btn-success" th:href="@{/add}">添加员工</a></h2>
  • class="btn btn-sm btn-success"  是按钮的样式
  • 点击后发送请求: /add

点击添加员工按钮后我们应该跳转到一个添加员工的页面/employee/add.html

@GetMapping("/add")public String addEmployee(){return "/employee/add";}
  • @GetMapping和@RequestMapping的区别是前者只能处理get请求,                                    同理还有@PostMapping 
<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4"><form class="form-horizontal"><div class="form-group"><label>id</label><div class="col-sm-10"><input class="form-control" name="id" placeholder="1000"></div></div><div class="form-group"><label>lastName</label><div class="col-sm-10"><input class="form-control" name="lastName" placeholder="韩"></div></div><div class="form-group"><label>email</label><div class="col-sm-10"><input class="form-control" name="email" placeholder="392851349@qq.com"></div></div><label>gender</label><select class="form-control" name="gender"><option>男</option><option>女</option></select><label>department</label><select class="form-control" name="department"><option>1</option><option>2</option><option>3</option><option>4</option><option>5</option></select><div class="form-group"><label>birth</label><div class="col-sm-10"><input class="form-control" name="birth" placeholder="1998/09/22"></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-default">添加</button></div></div></form></main>

 接下来有一个问题是,添加员工时,在部门下拉框那我们需要知道有哪些部门,因为部门是可以动态添加删除的

改写:

@AutowiredDepartmentDao departmentDao;@GetMapping("/add")public String addEmployee(Model model){//先需要查询出来所有的部门名称Collection<Department> departments = departmentDao.getDepartments();model.addAttribute("departments", departments);return "/employee/add";}
<label>department</label><select class="form-control" name="department"> <option th:each="department:${departments}" th:text="${department.getDepartmentName()}" th:value="${department.getId()}"></option></select>
  • text属性是这个下拉框的option标签显示出来的内容
  • value属性时这个下拉框的option标签所携带的值,
  • 设置value的目的是因为创建员工,为其添加对应的部门时,需要知道部门id才可以查询到部门对象
  • 通过thymeleaf的th:each来遍历后端传递过来的departments


  •  给表单加上action
<form class="form-horizontal" th:action="@{/add}" method="post">
  • form的method是post,所以 controller层用:@PostMapping("/add"),表示只能接收到post方式的/add请求
@PostMapping("/add")public String add(Employee employee){//添加员工的操作employeeDao.addEmployee(employee);System.out.println(employee);//表单提交后,需要重定向到展示员工列表的页面return "redirect:/employee";//重定向到/employee请求,即selectAllEmployees这个方法}
  • 提交表单后,先调用后台的添加员工方法,再重定向(重新查询一下全部员工列表) 

但是前端表单里输入的信息,springboot是怎么与employee对象的各个属性一一对应的?

add.html中表单部分:

<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4"><form class="form-horizontal" th:action="@{/add}" method="post"><div class="form-group"><label>lastName</label><div class="col-sm-10"><input class="form-control" name="lastName" placeholder="韩"></div></div><div class="form-group"><label>email</label><div class="col-sm-10"><input class="form-control" name="email" placeholder="392851349@qq.com"></div></div><label>gender</label><select class="form-control" name="gender"><option th:value="1">男</option><option th:value="0">女</option></select><label>department</label><select class="form-control" name="department.id"><option th:each="department:${departments}" th:text="${department.getDepartmentName()}" th:value="${department.getId()}"></option></select><div class="form-group"><label>birth</label><div class="col-sm-10"><input class="form-control" name="birth" placeholder="1998/09/22"></div></div><div class="form-group"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-default">添加</button></div></div></form></main>
  • name属性功不可没, 表单中的name属性要与实体类的属性名称一致。这样springboot就能将表单的input标签的输入与实体类的属性一一对应。
  • 在Springboot进行数据封装时,提交到后台的数据都是String型,对于基本的数据类型会自动转化
  • 实体类employee的字段必须包含表单中所有input的name对应的值,并且在类中为对应的字段生成getter 与setter方法
  • id不需要在前端填写,因为设置了自增
  • placeholder属性表示框内提示的信息

下面重点说一说两个<select>下拉框中选择的内容是怎么与对象employee的属性一一匹配的

<select class="form-control" name="gender"> <option th:value="1">男</option> <option th:value="0">女</option></select>
  •  会把所选中的<option>中的value值与对应对象的gender属性匹配
<select class="form-control" name="department.id"><option th:each="department:${departments}" th:text="${department.getDepartmentName()}" th:value="${department.getId()}"></option></select>
  • 会把  th:value="${department.getId()}"  中的值传递给  name="department.id"  ,注意这里department的id属性虽然是private,但是也必须这么写,不能写成 department.getId();
public class Employee {private Integer id;private String lastName;private String email;private Integer gender;//0女1男private Department department;private Date birth;}

        观察employee类就看出来,如果表单上输入与employee属性一一对应的话,上面表单里应该提交的是Department department,那为什么提交的是department.id。

        纠正一个上面的错误观点,不是要求表单上输入与employee属性一一对应,而是表单上输入与name属性的内容一一对应。

再来看下面:

@PostMapping("/add")public String add(Employee employee){//添加员工的操作employeeDao.addEmployee(employee);System.out.println(employee);//表单提交后,需要重定向到展示员工列表的页面return "redirect:/employee";//重定向到/employee请求,即selectAllEmployees这个方法}
  • 注意add方法有个Employee employee参数, 这个对象就是前端传过来的

employeeDao的addEmployee方法: 

//增加一个员工public void addEmployee(Employee employee){if(employee.getId()==null){employee.setId(initId++);}employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));employees.put(employee.getId(), employee);}
  • 从表单上获取的department.id被传入到addEmployee方法中去
    employee.setDepartment(departmentDao.getDepartmentById(employee.getDepartment().getId()));

 九、修改员工信息

功能:点击对应员工的 编辑 按钮,进入编辑员工界面


list.html: 

//跳转到编辑员工信息界面@RequestMapping("/edit")public String ToEdit(){return "/employee/edit";}

 

 但是在controller跳转到edit.html页面之前,必须先要获取到这个被编辑的员工的信息,展示到edit.html中。


 所以上面的代码需要调整为:

list.html:

  •  向后台发送请求的同时,发送当前待编辑对象的id参数,这样的话后台就可以根据employee的id,把这个employee的信息查询出来,显示到编辑页面edit.html
//跳转到编辑员工信息界面@GetMapping("/edit/{id}")public String ToEdit(@PathVariable("id")Integer id, Model model){//编辑员工的页面要先展示这个员工的信息Employee employee = employeeDao.getEmployeeById(id);model.addAttribute("emp", employee);Collection<Department> departments = departmentDao.getDepartments();model.addAttribute("departments", departments);return "/employee/edit";}
  •   @GetMapping("/edit/{id}")中的{id}是占位符,与th:href="@{/edit/}+${emp.id}"中的emp.id对应
  • @PathVariable("id")Integer id是在获取前端数据,Model是给前端传数据

  • @PathVariable的使用参考:参考1  参考2   参考3

  • model.addAttribute("emp", employee);和model.addAttribute("departments", departments);中的"emp"、"departments"都是只在return的html页面内可以获取到的,其他页面获取不到

edit.html

  • <input>中的th:value="${emp.getLastName()}"表示:框内显示的默认值
  • <option>中的 th:selected="${表达式}",表示如果表达式为true,那么就默认选中该下拉框

 


剩下就是提交该表单的业务了

<form class="form-horizontal" th:action="@{/edit}" method="post">
  •  提交表单,发送 /edit 请求
  • 该请求被下面controller接收
//员工信息修改提交@RequestMapping("/edit")public String edit(Employee employee){employeeDao.addEmployee(employee);return "redirect:/employee";}
  • 添加该员工,再重定向到/employee请求 

但是上面的edit方法有一个问题是提交的员工不是修改原来的,而是增加了一个新的员工:

 解决办法:

在表单中加上上id的标签

<div class="col-sm-10"><input type="hidden" th:value="${emp.getId()}" class="form-control" name="id"></div>

 并设置隐藏,用户不能修改,这样的话新添加的employee就会覆盖原来的(从employeeDao中能看出来为啥这样可以覆盖原来的)


十、删除员工

list.html 

//删除员工@RequestMapping("/delete/{id}")public String delete(@PathVariable("id")Integer id){employeeDao.delete(id);return "redirect:/employee";}

不多赘述

十一、404页面

 springboot中,只需要在templates文件下添加一个名为404.html的页面,在404的时候会自动定位到这个页面并显示。

回帖
全部回帖({{commentCount}})
{{item.user.nickname}} {{item.user.group_title}} {{item.friend_time}}
{{item.content}}
{{item.comment_content_show ? '取消' : '回复'}} 删除
回帖
{{reply.user.nickname}} {{reply.user.group_title}} {{reply.friend_time}}
{{reply.content}}
{{reply.comment_content_show ? '取消' : '回复'}} 删除
回帖
收起
没有更多啦~
{{commentLoading ? '加载中...' : '查看更多评论'}}