项目介绍:
用SpringBoot实现一个员工管理系统
一、准备工作
1.1 这部分素材来源于BootStrap网站https://getbootstrap.com/docs/4.0/examples/
1.2 创建数据库
1.3 创建一个SpringBoot项目,并配置好相应的环境
二、首页实现
这里涉及静态资源导入的问题,通过查看源码,可以得知,只有在
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public
才可以默认导入,在本次项目中,将静态资源(页面)放到/resources/templates下,可以通过以下两种方式配置来进行访问:
- Controller中配置
- 自定义WebMvcConfigurer配置类
导入Thymeleaf 模板引擎
- pom中导入依赖项
- 添加命名空间
- 用Thymeleaf 语法替换本地资源部分,如果引用的是网络上的资源,不需要使用这种形式。
Controller配置
1.作用:控制器类,处理由DispatcherServlet分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Model返回给对应的View进行展示。
与Controller配合使用的关键字还有GetMapping,PostMapping, RequestMapping等用于获取请求的注解。
WebMvcConfigurer 配置
这一步主要做了以下几点:
-
@Configuration:这个注解修饰的类,说明该类是一个Spring配置类
-
implements WebMvcConfigurer:实现该接口,可以用来扩展WebMvcConfigurer的配置
-
public void addViewControllers(ViewControllerRegistry registry) {}:重写addViewControllers()方法,添加一个视图控制器
-
registry.addViewController("/").setViewName(“index”);:添加视图控制,设置url-pattern,指向视图index。(前缀和后缀在Thymeleaf视图解析器中默认设置)
这里就不详细说了,详情可参考我的这篇博文
WebMvcConfigurer 配置
三、国际化
国际化指的是页面可以实现多语言展示,既可以显示中文,又可以显示英文页面或者其它语言。
注意:实现国际化之前,要保证项目编码使用的是UTF-8,否则可能会出现中文乱码问题。
- 编写中英文的properties配置文件
- 在application.yml中设置消息的basename来引用刚刚的配置文件,basename指向国际化文件的真实位置
- 修改HTML中的文本引用
- 配置SpringBoot中的区域解析器
这里详细说一下区域解析器的配置
解读:WebMvcAutoConfiguration类中的localeResolver()方法:
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
return new FixedLocaleResolver(this.mvcProperties.getLocale());
}
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
return localeResolver;
- 如果我们在配置文件中配置了mvcProperties的属性,则会根据配置文件来配置LocaleResolver对象
- 如果配置文件没有配置,则返回一个默认的LocaleResolver
因为我们没有在application.yaml中配置关于区域的属性,所以SpringBoot会使用默认的LocaleResolver。
看一下默认的区域解析器是怎么生成的:
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
是通过实例化AcceptHeaderLocaleResolver对象,设置默认的区域配置来生成的区域解析器。
打开AcceptHeaderLocaleResolver类看一下:
public class AcceptHeaderLocaleResolver implements LocaleResolver {
这个类实现了LocaleResolver接口,并实现了resolveLocale()方法:
@Override
public Locale resolveLocale(HttpServletRequest request) {
Locale defaultLocale = getDefaultLocale();
if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
return defaultLocale;
}
Locale requestLocale = request.getLocale();
List<Locale> supportedLocales = getSupportedLocales();
if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
return requestLocale;
}
Locale supportedLocale = findSupportedLocale(request, supportedLocales);
if (supportedLocale != null) {
return supportedLocale;
}
return (defaultLocale != null ? defaultLocale : requestLocale);
}
所以,我们也可以自定义一个类来实现LocaleResolver这个接口,并重现接口中的方法,这就是我们自定义的区域解析器:
public class MyLocaleResolver implements LocaleResolver {
/**
* 解析请求
*
* @param request
* @return
*/
@Override
public Locale resolveLocale(HttpServletRequest request) {
//获取请求参数
String lang = request.getParameter("lang");
// System.out.println("lang:"+lang);
Locale locale = Locale.getDefault();
if (!StringUtils.isEmpty(lang)) {
String[] split = lang.split("_");
locale = new Locale(split[0], split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
当我们定义完视图解析器后,需要到MyMvcConfig配置类中将区域解析器注册到IoC容器中,让解析器生效。
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
/**
* 添加视图控制器
*
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
System.out.println("come in ");
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
registry.addViewController("/main").setViewName("dashboard");
registry.addViewController("/main.html").setViewName("dashboard");
}
/**
* 添加自定义的区域解析器
*
* @return
*/
@Bean
public LocaleResolver localeResolver() {
return new MyLocaleResolver();
}
}
四、页面登录、注销
登录登出,如果登录成功,页面将跳转到dashboard;
登录不成功,设置一个msg提示消息,并跳转到index页面。
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
@Controller //处理http请求
public class LoginController {
/**
* 登录验证
*
* @param username
* @param password
* @param model
* @param session
* @return
*/
@PostMapping("/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password,
Model model,
HttpSession session) {
if ("admin".equals(username) && "123".equals(password)) {
session.setAttribute("loginUser", username);
return "redirect:/main.html";
} else {
model.addAttribute("msg", "用户名或密码错误");
return "index";
}
}
/**
* 注销登录
*
* @return
*/
@GetMapping("/logout")
public String logout(HttpSession session, Model model) {
session.invalidate();
model.addAttribute("msg", "注销成功");
return "redirect:/index.html";
}
}
登录成功后,在后台页面的地址栏中显示的仍然是带有请求参数的URL,这样看着就很不和谐。所以这里采用重定向来解决和这个问题,登录成功后重定向到首页。
五、登录拦截器
拦截器在学习SpringMVC时就已经接触过,可以通过拦截器实现对登录的拦截,只有登录成功才可以访问后台页面,否则不能直接访问后台页面。
在这里主要是采用对接口HandlerInterceptor进行实现,查看源码
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
- preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
- postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了);
- afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);
本次登录拦截采用实现HandlerInterceptor接口的preHandle方法即可。首先在登录的时候,我们会选择在session域中存储一个属性loginUser,用于拦截器判断拦截的依据:
if ("admin".equals(username) && "123".equals(password)) {
//登录成功,存储"loginUser"属性
session.setAttribute("loginUser",username);
return "redirect:/main";
}
在config包下新建登录拦截器,自定义类实现HandlerInterceptor接口,实现preHandle方法:
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//登录成功之后,应该有用户的Session
String loginUser = (String) request.getSession().getAttribute("loginUser");
if (loginUser == null) {
request.setAttribute("msg", "没有权限,请先登录");
request.getRequestDispatcher("/").forward(request, response);
return false; //不放行
}
return true; //放行
}
}
登录拦截是属于WebMvcConfigure接口中的一个方法,需要在视图解析器里面进行重写,把自定义的拦截器注入到IoC容器中。把要放行的资源路径都添加进来,包括静态资源,否则样式等等都会被拦截。
这一步相当于Spring在xml中配置拦截器。
/**
* 添加自定义的拦截器LoginHandlerInterceptor
* 指定要拦截和放行的资源
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/*")
.excludePathPatterns("/", "/index.html", "/login", "/css/*", "/img/*", "/js/*", "/emp/*");
}
六、展示员工列表
1. 首先进行数据库连接
有关mybatis-springboot整合的详细部分,详情可参考我的这篇博客
SpringBoot整合JDBC, Mybatis框架
2. 抽取页面公共部分
这里主要就是采用thymeleaf模板引擎中的替换语法,可支持传参功能
th:replace="~{commons/commons::sidebar(active='main')}"
3. 员工列表展示
在controller包下新建一个控制器EmployeeController,用来获取员工数据并跳转到list.html页面:
@Controller
public class EmployeeController {
@Autowired
private EmployeeMapper employeeMapper;
List<String> departmentsPermanent = Arrays.asList("部门1","部门2","部门3","部门4","部门5");
/**
* 获取所有员工数据,并在model中添加emps属性,将获取到的员工集合放进去
*
* @param model
* @return
*/
@RequestMapping("/emps")
public String list(Model model) {
Collection<Employee> employees = employeeMapper.queryEmps();
model.addAttribute("emps", employees);
return "emp/list";
}
}
七. 增加员工展示
这里主要就两个操作,一个是点击添加员工按钮后,携带相应的数据并跳转到添加页面,然后在添加页面点击提交按钮后,再添加数据保存到数据库中。
/**
* 获取"添加员工"页面
*
* @return
*/
@GetMapping("/add")
public String getAddPage(Model model) {
//获取所有部门信息
Collection<Employee> employees = employeeMapper.queryEmps();
//将部门信息添加到model中
// model.addAttribute("employees", employees);
model.addAttribute("departmentsPermanent", departmentsPermanent);
return "emp/add";
}
/**
* 执行添加员工操作
*
* @param employee
* @return
*/
@PostMapping("/add")
public String addMethod(Employee employee) {
employeeMapper.addEmp(employee);
return "redirect:/emps";
}
八. 修改员工信息
这里主要就两个操作,一个是点击修改编辑按钮后,携带相应的数据并跳转到修改页面,然后在修改页面点击提交按钮后,再将修改的数据保存到数据库中。
/**
* 更新员工信息
*
* @param employee
* @return
*/
@PostMapping("/update")
public String updateMethod(Employee employee) {
employeeMapper.updateEmp(employee);
return "redirect:/emps";
}
/**
* 通过员工id删除员工
*
* @param id
* @return
*/
@GetMapping("/delete/{id}")
public String deleteMethod(@PathVariable("id") Integer id) {
employeeMapper.deleteEmpById(id);
return "redirect:/emps";
}
九. 修改员工信息及404页面
点击删除按钮后,直接调用删除功能,把数据删除即可
/**
* 通过员工id删除员工
*
* @param id
* @return
*/
@GetMapping("/delete/{id}")
public String deleteMethod(@PathVariable("id") Integer id) {
employeeMapper.deleteEmpById(id);
return "redirect:/emps";
}
添加404页面非常简单,只需要在templates目录下新建error文件夹,在里面添加404.html即可,当前端访问出现404时,会跳转到这个页面。
稍后我会将所有源代码包括sql创建等上传
参考资料:
https://javabook.shiguangping.com/