基于springboot的一个简略员工管理系统实现

环境配置

常用三注解辨析

注解参数来源用途
@PathVariableURL 路径的一部分获取资源 ID 或路径里的动态变量
@RequestParamURL 中 ? 后面的参数(Query String),或表单获取简单的 key-value 参数(name=xxx)
@RequestBodyHTTP 请求体(JSON)获取整个 JSON 内容,并反序列化成对象

参数来源

注解参数来自哪里
@PathVariableURL 路径
@RequestParamURL 参数 / 表单
@RequestBodyJSON 请求体

使用场景:

场景推荐使用
删除、更新某个资源@PathVariable
分页/搜索/筛选@RequestParam
提交表单(JSON)

@RequestBody

是否接收JSON

注解能否接收 JSON
@PathVariable❌ 不支持
@RequestParam❌ 不支持
@RequestBody✅ 用于 JSON

能否接收大量数据

注解接大量字段?
@PathVariable❌(只适合单个值)
@RequestParam⚠️ 不适合(字段多会很乱)
@RequestBody✅ 最合适(JSON)

部门管理接口实现

controller层

package com.itheima.controller;

import com.itheima.pojo.Dept;
import com.itheima.pojo.Result;
import com.itheima.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@Slf4j
@RequestMapping("/depts")          //抽取公共路径
/*
 ---  在类中抽取公共路径,实际方法路径为Request内的value值 + 具体方法的value值   ---
*/
@RestController
public class DeptController {

    @Autowired
    DeptService deptService;
                   //    @RequestMapping(value = "/depts",method = RequestMethod.GET)
                   //      限定请求方式为get
    @GetMapping//       ("/depts"),公共路径被抽取
    public Result list(){
        log.info("查询员工信息");

        List<Dept> allList = deptService.list();
        return Result.success(allList);
    }
    //限定请求方式为delete
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id){
        log.info("删除员工{}",id);
        deptService.delete(id);
        return Result.success();
    }

    @PostMapping
    public Result add(@RequestBody Dept dept)//  注解表示接收参数为JSON格式的dept类
    {
        log.info("新增部门:{}",dept);
        deptService.add(dept);
        return Result.success();
    }

    @GetMapping("/{id}")
    public Result selectById(@PathVariable Integer id){
        log.info("根据{}查询数据",id);
        Dept dept = deptService.selectById(id);
        return Result.success(dept);
    }
    @PutMapping
    public Result update(@RequestBody Dept dept){
        log.info("修改部门:{}",dept);
        deptService.update(dept);
        return Result.success();
    }
}

service层实现类

package com.itheima.service.impl;

import com.itheima.mapper.DeptMapper;
import com.itheima.pojo.Dept;
import com.itheima.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class DeptServicelmpl implements DeptService {

    @Autowired
    DeptMapper deptMapper;
    @Override
    public List<Dept> list() {
        List<Dept> allList = deptMapper.list();
        return allList;
    }

    @Override
    public void delete(Integer id) {
        deptMapper.deleteByID(id);
    }

    @Override
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.add(dept);
    } //进行属性补充(部门除了传递的参数名称外还有创建时间,更新时间等属性)

    @Override
    public void update(Dept dept) {
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.update(dept);
    }

    @Override
    public Dept selectById(Integer id) {
        return deptMapper.selectById(id);
    }
}

service层接口

package com.itheima.service;

import com.itheima.pojo.Dept;

import java.util.List;

public interface DeptService {
    List<Dept> list();

    void delete(Integer id);

    void add(Dept dept);

    void update(Dept dept);

    Dept selectById(Integer id);
}

接口

package com.itheima.mapper;

import com.itheima.pojo.Dept;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface DeptMapper {

    @Select("select * from dept")
    List<Dept> list();

    @Delete("delete from dept where id = #{id}")
    void deleteByID(Integer id);

    @Insert("insert into dept(name, create_time, update_time) VALUES (#{name}, #{createTime}, #{updateTime})")
    void add(Dept dept);

    @Update("update dept set name = #{name}, update_time = #{updateTime} where id = #{id}")
    void update(Dept dept);

    @Select("select * from dept where id = #{id}")
    Dept selectById(Integer id);
}

 

员工管理接口实现

MySQL中分页查询语法

PageHelper插件

基于pagehelper的mapper接口

@Mapper
public interface EmpMapper {
/*   不使用插件mapper部分代码实现
    @Select("select count(*) from emp")
    public Long count();

    @Select("select * from emp limit #{start}, #{pageCount}")
    public List<Emp> page(int start, int pageCount);
*/

    //员工信息查询
    @Select("select * from emp")
    public List<Emp> list();
}

基于pagehelper的service接口

@Service
public class EmpServicelmpl implements EmpService {

    @Autowired
    EmpMapper empMapper;
/*  不使用pagehelper插件的代码实现
    @Override
    public PageBean page(int page, int pageSize) {
        //获取记录总数
        Long count = empMapper.count();

        //返回查询数据列表
        int start = (page - 1) * pageSize;
        List<Emp> list= empMapper.page(start,pageSize);
        return new PageBean(count,list);
    }

 */
    @Override
    public PageBean page(int page, int pageSize) {
        //设置分页参数
        PageHelper.startPage(page,pageSize);

        //执行查询
        List<Emp> emplist = empMapper.list();
        Page<Emp> p = (Page<Emp>)emplist;

        //封装pageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }
}

员工分页查询

controller层

package com.itheima.controller;

import com.itheima.pojo.Emp;
import com.itheima.pojo.PageBean;
import com.itheima.pojo.Result;
import com.itheima.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDate;
import java.util.List;

@Slf4j
@RestController
public class EmpController {

    @Autowired
    EmpService empService;

    @GetMapping("/emps")
    public Result page(@RequestParam(defaultValue = "1") int page,
                       @RequestParam(defaultValue = "10") int pageSize,
                        String name, Short gender,
                        @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
        log.info("分页查询:{},{}", page, pageSize);
        PageBean pagebean = empService.page(page,pageSize,name,gender,begin,end);
        return Result.success(pagebean);
    }
}

service接口及其实现类层

package com.itheima.service;

import com.itheima.pojo.PageBean;

import java.time.LocalDate;

public interface EmpService {
    PageBean page(int page, int pageSize, String name, Short gender, LocalDate begin, LocalDate end);
}

package com.itheima.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.Emp;
import com.itheima.pojo.PageBean;
import com.itheima.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.List;

@Service
public class EmpServicelmpl implements EmpService {

    @Autowired
    EmpMapper empMapper;
/*  不使用pagehelper插件的代码实现
    @Override
    public PageBean page(int page, int pageSize) {
        //获取记录总数
        Long count = empMapper.count();

        //返回查询数据列表
        int start = (page - 1) * pageSize;
        List<Emp> list= empMapper.page(start,pageSize);
        return new PageBean(count,list);
    }

 */
    @Override
    public PageBean page(int page, int pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
        //设置分页参数
        PageHelper.startPage(page,pageSize);

        //执行查询
        List<Emp> emplist = empMapper.list(name, gender, begin, end);
        Page<Emp> p = (Page<Emp>)emplist;

        //封装pageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }
}

mapper接口及其xml映射文件

package com.itheima.mapper;

import com.itheima.pojo.Emp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.time.LocalDate;
import java.util.List;

@Mapper
public interface EmpMapper {
/*   不使用插件mapper部分代码实现
    @Select("select count(*) from emp")
    public Long count();

    @Select("select * from emp limit #{start}, #{pageCount}")
    public List<Emp> page(int start, int pageCount);
*/

    //员工信息查询
    public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">
    <select id="list" resultType="com.itheima.pojo.Emp">
        select * from emp
        <where>
            <if test="name != null and name !='' ">
                name like concat('%', #{name}, '%')
            </if>
        <if test="gender != null and gender !='' ">
            and gender = #{gender}
        </if>
        <if test="begin != null and end != null">
        and entrydate between #{begin} and #{end}
        </if>
        </where>
        order by update_time desc
    </select>
</mapper>

员工批量删除

controller层

 @DeleteMapping("/{ids}")
    public Result delete(@PathVariable List<Integer> ids) {
        log.info("删除员工");
        empService.delete(ids);
        return Result.success();
    }

service接口及其实现类

//service接口
    void delete(List<Integer> ids);
    //service实现类
    @Override
    public void delete(List<Integer> ids) {
        empMapper.delete(ids);
    }

mapper接口及其映射文件

void delete(List<Integer> ids);
<!--    批量删除员工     -->
    <delete id="delete">
        delete from emp where id in
        <foreach collection="ids" item="id" open="(" close=")" separator=",">
        #{id}
        </foreach>
    </delete>

文件上传

 

前端页面html文件存放处

服务端

本地存储

服务器接收到上传的文件后将文件存储到本地磁盘中

@Slf4j
@RestController
public class UploadController {

    @PostMapping("/upload")
    public Result upload(String username, Integer age, MultipartFile image) throws Exception {
        log.info("文件上传:{} {} {}", username, age, image);
        //获取原始文件名
        String originalFilename = image.getOriginalFilename();
        //构造唯一文件名(不能重复)--uuid(唯一通用识别码)
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));//获取文件拓展名
        String newFileName = UUID.randomUUID().toString() + suffix;
        log.info("新获得的文件名{}", newFileName);
        //将文件储存在本地磁盘里
        image.transferTo(new File("D:\\java\\" + newFileName));
        return Result.success();
    }
}

修改可上传存储文件的最大大小:配置大小文件

#单个文件上传的最大大小
spring.servlet.multipart.max-file-size=10MB
#单词请求上传的最大大小(可上传多个文件)
spring.servlet.multipart.max-request-size=100MB

云存储(后续补充)

新增员工(需要上传员工图片)

修改员工

根据id查询数据实现数据回显

   //controller层
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("查询员工信息:{}",id);
        Emp emp = empService.getById(id);
        return Result.success(emp);
    }

//service层
    //根据id查询员工
    Emp getById(Integer id);

    @Override
    public void update(Emp emp) {
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.update(emp);
    }
//mapper层
    @Select("select * from emp where id = #{id}")
    Emp getById(Integer id);

根据id修改员工

   //controller层
    @PutMapping
    public Result update(@RequestBody Emp emp) {
        log.info("更新员工:{}",emp.toString());
        empService.update(emp);
        return Result.success();
    }

//service层
      void update(Emp emp);

    @Override
    public void update(Emp emp) {
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.update(emp);
    }
//mapper层及其xml映射文件
    void update(Emp emp);
    <!--    修改员工    -->
    <update id="update">
        update emp
            <set>
            <if test="image != null">
                image = #{image},
            </if>
            <if test="username != null">
                username = #{username},
            </if>
            <if test="name != null">
                name = #{name},
            </if>
            <if test="gender != null">
                gender = #{gender},
            </if>
            <if test="job != null">
                job = #{job},
            </if>
            <if test="entryDate != null">
                entrydate = #{entryDate},
            </if>
            <if test="deptId != null">
                dept_Id = #{deptId},
            </if>
            <if test="updateTime != null">
                update_time = #{updateTime}
            </if>
            </set>
       where id = #{id}
    </update>

配置文件

将参数配置在配置文件中,以后修改参数只需要在配置文件中修改,通过@Value注解注入给成员变量,无需再手动修改成员变量经过编译。

配置格式

不同配置文件的区别

yml配置文件(最常使用)

yml数据格式

server:
  port: 9000

#定义对象/map集合
user:
  name: Tom
  age: 20
  address: beijing

#定义数组/集合
#数组名
hobby:
  -java
  -c
  -game
  -sport
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/talis
    username: root
    password: 123456
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 100MB

mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true

ConfigurationProperties配置文件:

通过ConfigurationProperties配置配置项前缀,一次注入属性值,可以避免通过Value注解一个一个注入实体类的属性值(配置文件名与成员变量名要一致)

ConfigurationProperties与Value注解区别:

单个注入与批量注入

登录校验

登录

校验

基本流程

会话技术

会话:浏览器访问web服务器资源,会话建立,在会话中可以有多次请求响应,直到断开连接,会话结束

会话跟踪:服务器识别多次请求是否同一浏览器发出,以便在同一会话中实现请求响应的数据共享

cookie

跨域操作

session

项目CookieSession
存储位置浏览器服务器内存
安全性
是否携带敏感数据❌ 不建议✔ 可存登录信息
大小限制有(4KB)服务器内存决定
生命周期由浏览器控制由服务器控制(30min)
是否依赖 Cookie——✔ 依赖 JSESSIONID

 

项目SessionToken
状态存储服务器内存客户端保存,服务器无状态
跨端兼容(APP/浏览器)不方便非常方便
分布式扩展需要共享 Session天然支持
安全性中等可更高(签名/加密)

令牌(Token)

JWT令牌⭐️⭐️

JWT令牌生成校验:

引入依赖

<dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.12.3</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.12.3</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.12.3</version>
            <scope>runtime</scope>
        </dependency>
 public void testJWT() {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", "zhangsan");
        claims.put("password", "123456");
        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256,"fQk0YH6vJWLQv2Nv62zyqm7EaY5kU0+FLwA+IqK7i7Y=")//签名算法
                .setClaims(claims)//自定义内容(载荷)
                .setExpiration(new Date(System.currentTimeMillis() + 3600*1000))//设置令牌有效期
                .compact();
        System.out.println(jwt);
    }

    @Test
    public void testParseJWT() {
        Claims claim = Jwts.parser()
                .setSigningKey("fQk0YH6vJWLQv2Nv62zyqm7EaY5kU0+FLwA+IqK7i7Y=")
                .build()
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMzQ1NiIsInVzZXJuYW1lIjoiemhhbmdzYW4iLCJleHAiOjE3NjM4ODgwNzl9.7HrYrsOtlFdmtB6knvrKhsreL0EV4aOL4aOwATS_g-k")
                .getBody();
        System.out.println(claim);
    }

令牌非法与报错:

登录后下发令牌

 

filter(过滤器)

步骤

filter类

package com.itheima.filter;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;

import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class DemoFilter implements Filter{
    @Override//初始化方法,只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("DemoFilter init");
    }

    @Override//拦截到请求后调用,调用多次
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter");
        //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override//销毁方法,只调用一次
    public void destroy() {
        System.out.println("DemoFilter destroy");
    }
}

//启动类注解
@ServletComponentScan//使用三大组件必须加入的注解(filter/listener/servlet),开启对servlet组件的支持
@SpringBootApplication

filter执行流程详解

拦截路径

过滤器链

配置多个过滤器,实现多个过滤器

登录校验功能实现

过滤器流程

@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //获取url
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String url = request.getRequestURI().toString();
        log.info("登录请求{}", url);
        //判断是否为登录操作
        if (url.contains("login")) {
            log.info("登录操作,放行");
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        //不是登录操作,获取请求头令牌
        String jwt = request.getHeader("token");
        //是否有请求头令牌
        if (!StringUtils.hasLength(jwt)) {
            //没有请求头令牌,未登录
            log.info("无令牌,返回未登录错误信息");
            Result error = Result.error("NOT_LOGIN");
            //手动将对象转为JSON格式数据 -->阿里巴巴fastJSON依赖
            String json = JSONObject.toJSONString(error);
            response.getWriter().write(json);
            return;
        }
        //解析token
        try {
            JwtUtils.parseJWT(jwt);
        } catch (Exception e) {
            log.info("解析令牌失败,返回未登录错误信息");
            Result error = Result.error(jwt);
            //手动将对象转为JSON格式数据 -->阿里巴巴fastJSON依赖
            String NOT_LOGIN = JSONObject.toJSONString(error);
            response.getWriter().write(NOT_LOGIN);
            return;
        }
        //放行
        log.info("令牌合法,放行");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

Interceptor(拦截器) ⭐️⭐️

拦截器简介

作用类似于过滤器

 

使用步骤:

1.创建拦截器,继承HandleInterceptor接口并重写方法

2.注册配置拦截器:创建配置类,实现接口WebMvcConfiguration,加上Configuration注解注明是一个配置类

 

Interceptor流程详解

拦截路径

拦截流程

异常处理

全局异常处理器

 

//全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandle {

    @ExceptionHandler(Exception.class)//捕获异常的类型
    public Result ex(Exception ex){
        ex.printStackTrace();
        return Result.error("操作失败");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值