本次功能代码实现(免费)
此时我们还什么都没有做,项目开发还在初始阶段!
只是配置的了SpringBoot静态资源放行路径
可以看到我们点击登入按钮的时候,请求的路径是:http://localhost:8080/employee/login
并且是post请求
我们的后台代码还没有编写,所以这里就报404
故我们现在应该按照三层架构的方式来构建后台逻辑
在上述的前端代码中, 大家可以看到, 发送登录的异步请求之后, 获取到响应结果, 在响应结果中至少包含三个属性: code、data、msg
所在的包:com.harmony.reggie.entity
- @Data
- @Setter
- @Getter
- public class Employee {
-
- // serialVersionUID用作Serializable类中的版本控件
- // JavaBean规范中要实现java.io.Serializable接口实现序列化!!!
- private static final long serialVersionUID = 1L;
-
- private Long id;
-
- private String username;
-
- private String name;
-
- private String password;
-
- private String phone;
-
- private String sex;
-
- // 数据库里面是id_number 在application.yml配置即可,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
- private String idNumber;
-
- private Long status;
-
- // LocalDateTime : JDK8 线程安全
- private LocalDateTime createTime;
-
- private LocalDateTime updateTime;
-
- // MP中用于标识非主键的字段。将数据库列与 JavaBean 中的属性进行映射,
- // fill 字段填充标记,表示在插入时自动填充
- @TableField(fill = FieldFill.INSERT)
- private Long createUser;
-
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Long updateUser;
- }
serialVersionUID:用作Serializable类中的版本控件,表示该类为可序列化类!JavaBean规范中要实现java.io.Serializable接口实现序列化(序列化serialVersionUID解释说明)
idNumber:数据库里面是id_number 在application.yml配置即可,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
@TableField(fill = FieldFill.INSERT):MP中用于标识非主键的字段。将数据库列与 JavaBean 中的属性进行映射,fill 字段填充标记,表示在插入时自动填充。
此类是一个通用结果类,服务端响应的所有结果最终都会包装成此种类型返回给前端页面。
所在的包:com.harmony.reggie.common
- /**
- * 通用返回结果,服务端返回的数据最终会封装成此对象
- * @param
- */
- @Data
- public class R
{ -
- private Integer code; //编码:1成功,0和其它数字为失败
-
- private String msg; //错误信息
-
- private T data; //数据
-
- private Map map = new HashMap(); //动态数据
-
- public static
R success(T object) { - R
r = new R(); - r.data = object;
- r.code = 1;
- return r;
- }
-
- public static
R error(String msg) { - R r = new R();
- r.msg = msg;
- r.code = 0;
- return r;
- }
-
- public R
add(String key, Object value) { - this.map.put(key, value);
- return this;
- }
-
- }
所在的包:com.harmony.reggie.controller
- @Slf4j
- @RestController
- @RequestMapping("/employee")
- public class EmployeeController {
-
- @Autowired
- private EmployeeService employeeService;
-
- /**
- * 员工登入
- * @param request
- * @param employee
- * @return
- */
- @PostMapping("/login")
- public R
login(HttpServletRequest request, @RequestBody Employee employee) { - // @RequestBody : 用来接收前端传递给后端的json字符串中的数据的
- return employeeService.login(request,employee);
- }
- }
所在的包:com.harmony.reggie.mapper
在MybatisPlus中, 自定义的Mapper接口, 需要继承自 BaseMapper
- @Mapper
- public interface EmployeeMapper extends BaseMapper
{ - }
所在的包:com.harmony.reggie.service
本项目的Service接口, 在定义时需要继承自MybatisPlus提供的Service层接口 IService, 这样就可以直接调用 父接口的方法直接执行业务操作, 简化业务层代码实现。
- public interface EmployeeService extends IService
{ -
- R
login(HttpServletRequest request, Employee employee); -
- }
该功能的业务逻辑都在这里了!
①. 将页面提交的密码password进行md5加密处理, 得到加密后的字符串
②. 根据页面提交的用户名username查询数据库中员工数据信息
③. 如果没有查询到, 则返回登录失败结果
④. 密码比对,如果不一致, 则返回登录失败结果
⑤. 查看员工状态,如果为已禁用状态,则返回员工已禁用结果
⑥. 登录成功,将员工id存入Session, 并返回登录成功结果
所在的包:com.harmony.reggie.service.impl
- @Service
- public class EmployeeServiceImpl extends ServiceImpl
implements EmployeeService { -
- @Autowired
- private EmployeeMapper employeeMapper;
-
- @Override
- public R
login(HttpServletRequest request, Employee employee) { - // 1. 将页面提交的密码password进行md5加密处理, 得到加密后的字符串
- String password = employee.getPassword();
- password = DigestUtils.md5DigestAsHex(password.getBytes());
-
- // 2. 根据页面提交的用户名username查询数据库中员工数据信息
- LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper<>(); -
- // Employee::getUsername 查询SQL表里面的用户名
- // employee.getUsername() 获取JavaBean的用户名
- // eq()表示查询符合条件的数据
- queryWrapper.eq(Employee::getUsername,employee.getUsername());
- Employee emp = employeeMapper.selectOne(queryWrapper);
-
- // 3. 如果没有查询到, 则返回登录失败结果 || 密码比对,如果不一致, 则返回登录失败结果
- if(emp == null || !emp.getPassword().equals(password)){
- return R.error("登入失败");
- }
-
- // 4. 查看员工状态,如果为已禁用状态,则返回员工已禁用结果
- if(emp.getStatus() == 0) {
- return R.error("账号已禁用");
- }
-
- // 6. 登录成功,将员工id存入Session, 并返回登录成功结果
- request.getSession().setAttribute("employee",emp.getId());
- return R.success(emp);
- }
-
- }
但是这里面有几个点需要注意一下!
queryWrapper.eq(Employee::getUsername,employee.getUsername());
Employee::getUsername :用于获取对象属性名,即获取到的值就是employee类的 “username”属性名。
eq():第一个参数为表列名,第二个为你的条件
在登入功能里面有一些公用的类已经写了,这里有不重复说明了!
所在的包:com.harmony.reggie.controller
- @Slf4j
- @RestController
- @RequestMapping("/employee")
- public class EmployeeController {
-
- @Autowired
- private EmployeeService employeeService;
-
- /**
- * 员工退出
- * @param request
- * @return
- */
- @PostMapping("/logout")
- public R
logout(HttpServletRequest request) { - return employeeService.logout(request);
- }
- }
所在的包:com.harmony.reggie.service
- public interface EmployeeService extends IService
{ -
- R
logout(HttpServletRequest request); - }
所在的包:com.harmony.reggie.service.impl
- @Service
- public class EmployeeServiceImpl extends ServiceImpl
implements EmployeeService { -
- @Autowired
- private EmployeeMapper employeeMapper;
-
- @Override
- public R
logout(HttpServletRequest request) { - request.getSession().removeAttribute("employee");
- return R.success("退出成功");
- }
-
- }
前面我们已经完成了后台系统的员工登录功能开发,但是目前还存在一个问题,如下图所示:
上述这种设计并不合理,我们希望看到的效果应该是,只有登录成功后才可以访问系统中的页面,如果没有登录, 访问系统中的任何界面都直接跳转到登录页面。
A. 获取本次请求的URI
B. 判断本次请求, 是否需要登录, 才可以访问
C. 如果不需要,则直接放行
D. 判断登录状态,如果已登录,则直接放行
E. 如果未登录, 则返回未登录结
所在的包:com.harmony.reggie.filter
- /**
- * 检查用户是否已经完成登入
- *
- * @WebServlet : 声明一个自定义的 Servlet
- * @WebFilter : 声明一个Servlet 过滤器
- * @WebListener : 声明一个类为 Servlet 监听器
- */
- @WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*")
- @Slf4j
- public class LoginCheckFilter implements Filter {
-
- //路径匹配器,支持通配符
- public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
-
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- HttpServletRequest request = (HttpServletRequest) servletRequest;
- HttpServletResponse response = (HttpServletResponse) servletResponse;
-
- // 1. 获取本次请求的URI
- String requestURL = request.getRequestURI();
-
- log.info("拦截到的请求: {}", requestURL);
-
- // 定义可以放行的资源
- String[] urls = new String[]{
- "/employee/login",
- "/employee/logout",
- "/backend/**",
- "/front/**"
- };
-
- // 2. 判断本次请求, 是否需要登录, 才可以访问
- boolean check = check(urls, requestURL);
-
- // 3. 如果不需要,则直接放行
- if (check) {
- log.info("不需要处理的请求: {}", requestURL);
- filterChain.doFilter(request, response);
- return;
- }
-
- // 4. 判断登录状态,如果已登录,则直接放行
- if (request.getSession().getAttribute("employee") != null) {
- log.info("用户已登入,用户ID为: {}", request.getSession().getAttribute("employee"));
- filterChain.doFilter(request, response);
- return;
- }
-
- log.info("用户未登入...");
-
- // 5. 如果未登录, 则返回未登录结果,通过输出流的方式向客户端响应数据
- response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
- }
-
- /**
- * 路径匹配,检查本次请求是否需要放行
- *
- * @param urls
- * @param requestURI
- * @return
- */
- public boolean check(String[] urls, String requestURI) {
- for (String url : urls) {
- // URL匹配
- boolean match = PATH_MATCHER.match(url, requestURI);
- if (match) {
- return true;
- }
- }
- return false;
- }
- }
只有给启动类添加了这个注解上面配置的过滤器类才会交给Spring容器管理!
- @Slf4j
- @SpringBootApplication
- @ServletComponentScan
- public class ReggieApplication {
- public static void main(String[] args) {
- SpringApplication.run(ReggieApplication.class);
- log.info("项目启动成功...");
- }
- }
@ServletComponentScan、@WebServlet、@WebFilter、@WebListener
注意是在这个分支里面哦!!!
master是项目的主线,即项目最新的功能点实现情况!
可以的话请给个免费的star哦~~~谢谢
reggie_v2_BackendLogin