SpringBoot-Mybatis实战案例

目录

SpringBoot-Mybatis实战案例

1.部门查询

2.删除部门

3.新增部门 

4.修改部门 

5.分页查询 

6.条件分页查询 

7.删除员工

8.新增员工 

9.文件上传 (本地存储)

10.修改员工

(1)查询回显

(2)修改员工 

 11.配置文件

(1)参数配置化

(2)yml配置文件

(3)@ConfigurationProperties 

12.登录校验

(1)登录

(2)会话技术

 (3)JWT令牌

(4)过滤器Filter

(5)拦截器Intetor

(6)异常处理


SpringBoot-Mybatis实战案例

现在限制同时指定某个请求方式,可以使用注解@GetMapping和@PostMapping等。

准备条件:封装 Emp类、Dept类、Result类,数据库建表等。

1.部门查询

controller层:

@Slf4j
@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;
   // private static Logger log = LoggerFactory.getLogger(DeptController.class);
    @GetMapping(value = "/depts")
    public Result getDeptList(){
        log.info("查询所有部门信息");
        List<Dept> deptList = deptService.getDeptList();
        return Result.success(deptList);
    }
}

 service层: 

public interface DeptService {

    List<Dept> getDeptList();
}

service层实现类:

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    @Override
    public List<Dept> getDeptList() {
        return deptMapper.getDeptList();
    }
}

  mapper层:

@Mapper
public interface DeptMapper {
    @Select("select * from dept")
    List<Dept> getDeptList();
}

实现前后端联调测试:

2.删除部门

controller层:

    @DeleteMapping(value = "/depts/{id}")
    public Result deleteDept(@PathVariable Integer id){
        log.info("根据id删除部门:{}",id);
        deptService.deleteDept(id);
        return Result.success();

service层: 

 /*根据id删除部门信息*/
    void deleteDept(Integer id);

 service层实现类:

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

mapper层: 

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

实现前后端联调测试:

 

3.新增部门 

controller层:

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

 service层: 

   /*添加部门信息*/
    void addDept(Dept dept);

 service层实现类: 

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

 mapper层:

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

实现前后端联调测试:

4.修改部门 

controller层:

///修改部门
    @GetMapping("/{id}")
    public Result getByID(@PathVariable Integer id) {
        log.info("获取部门ID:{}",id);
        Dept dept = deptService.getByID(id);
        return Result.success(dept);
    }
    @PutMapping
    public Result updateDept(@RequestBody Dept dept){
        log.info("修改部门:{}",dept);
        deptService.updateDept(dept);
        return Result.success();
    }

  service层: 

 void updateDept(Dept dept);

 Dept getByID(Integer id);

   service层实现类: 

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

    @Override
    public Dept getByID(Integer id) {
        Dept dept = deptMapper.getByID(id);
        return dept;
    }

 mapper层:

 @Select("select * from dept where id = #{id}")
 Dept getByID(Integer id);
 @Update("update dept set name = #{name},update_time = #{updateTime} where id = #{id}")
 void updateDept(Dept dept);

实现前后端联调测试:

5.分页查询 

 封装PageBean类:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
    private Long total;
    private List rows;

}

controller层:

@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
    @Autowired
    private EmpService empService;
    @GetMapping
    public Result page(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pageSize) {
        log.info("分页查询,当前页码{},每页条数{}", page, pageSize);
        PageBean pageBean = empService.page(page, pageSize);
        return Result.success(pageBean);
    }
}

   service层: 

public interface EmpService {
    PageBean page(Integer page, Integer pageSize);
}

    service层实现类: 

Service
public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpMapper empMapper;
    @Override
    public PageBean page(Integer page, Integer pageSize) {
        //1.获取总记录数
        Long count = empMapper.count();
        //2.获取分页查询结果列表
        Integer start = (page - 1) * pageSize;
        List<Emp> rows = empMapper.page(start, pageSize);
        //3.将分页查询结果封装到PageBean对象中
        PageBean pageBean = new PageBean(count, rows);
        return pageBean;

    }
}

mapper层: 

@Mapper
public interface EmpMapper {
    @Select("select count(*) from emp")
    public Long count();
    @Select("select * from emp limit #{start},#{pageSize}")
    public List<Emp> page(Integer start, Integer pageSize);

}

实现前后端联调测试:

使用PageHelper插件

在pom.xml配置文件夹中,加入依赖

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

6.条件分页查询 

controller层:

@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
    @Autowired
    private EmpService empService;
    @GetMapping
    public Result page(@RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "10") Integer pageSize,
                       String name, Short gender,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
        log.info("分页查询参数:{},{},{},{},{},{}", page, pageSize, name, gender, begin, end);
        PageBean pageBean = empService.page(page, pageSize,name,gender,begin,end);
        return Result.success(pageBean);
    }
}

service层:

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

service层实现类:

@Service
public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpMapper empMapper;
    @Override
    public PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.执行查询
        List<Emp> empList = empMapper.page(name, gender, begin, end);
        Page<Emp> p = (Page<Emp>) empList;
        //3.将分页查询结果封装到PageBean对象中
        PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
        return pageBean;

    }
}

mapper层: 

public interface EmpMapper {
    //注意方法名要和xml文件<select>便签中id值相同
    public List<Emp> page(String name, Short gender, LocalDate begin, LocalDate end);
}

XML映射文件动态SQL: 

<?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.faw.mapper.EmpMapper">
    <select id="page" resultType="com.faw.pojo.Emp">
        select *
        from emp
        <where>
            <if test="name!=null and name!=''">
                name like concat('%',#{name},'%')
            </if>
            <if test="gender!=null">
                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>

动态SQL查询前后端联调:

7.删除员工

controller层:

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

service层:

 void delete(List<Integer> ids);

service层实现类:

@Override
    public void delete(List<Integer> ids) {
        empMapper.delete(ids);
    }

mapper层:

  void delete(List<Integer> ids);

XML映射文件动态SQL: 

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

动态SQL批量删除前后端联调:

8.新增员工 

controller层:

 @PostMapping
    public Result save(@RequestBody Emp emp) {
        log.info("新增员工:{}", emp);
        empService.save(emp);
        return Result.success();
    }

service层:

    void save(Emp emp);

service层实现类:

 @Override
    public void save(Emp emp) {
        emp.setCreateTime(LocalDateTime.now());
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.insert(emp);
    }

mapper层:

 //新增员工
    @Insert("insert into emp(username,name,gender,image,job,entrydate,dept_id,create_time,update_time)"+
            "values(#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
    void insert(Emp emp);

前后端联调:

9.文件上传 (本地存储)

服务端接收: 

必须保证表单的name和方法形参一致。 名称不一致就要加上注解@RequestParam进行参数绑定,里面所指定的value属性为前端所传的name参数名。

使用APIFox测试上传文件:

代码:

@RestController
@Slf4j
public class UploadController {
    @RequestMapping(value = "/upload")
    public Result upload(String username, Integer age, MultipartFile image) {
        log.info("{},{},{}", username, age, image);
        //将文件存储在本地E:\images目录下
        //1.拿到原始文件名
        String originalFilename = image.getOriginalFilename();
        //2.获取原始文件名最一个点的位置
        int index = originalFilename.lastIndexOf(".");
        //3.截取文件名
        String ext = originalFilename.substring(index);
        //4.拼接新的文件名,使用UUID
        String newFileName = UUID.randomUUID().toString() + ext;
        //5.日志输出新的文件名
        log.info("新文件名:{}", newFileName);
        //6.将文件存储到本地
        try {
            image.transferTo(new java.io.File("E:\\images\\" + newFileName));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Result.success();
    }

}

 测试已经将图片保存到本地,文件名使用UUID形式:

配置文件上传大小配置,在mybatis核心配置文件 application.properties中加入

#配置上传文件的配置项
#单个文件最大上传大小
spring.servlet.multipart.max-file-size=10MB
#所有文件最大上传大小
spring.servlet.multipart.max-request-size=10MB

10.修改员工

(1)查询回显

controller层:

@GetMapping("/{id}")
    public Result selectById(@PathVariable Integer id) {
        log.info("修改员工id为:{}", id);
        Emp emp = empService.selectById(id);
        return Result.success(emp);
    }

service层:

Emp selectById(Integer id);

service层实现类:

 @Override
    public Emp selectById(Integer id) {
        return empMapper.selectById(id);
    }

mapper层:

//查询回显
    @Select("select * from emp where id = #{id}")
    Emp selectById(Integer id);

前后端联调测试:

(2)修改员工 

controller层:

@PutMapping
    public Result update(@RequestBody Emp emp) {
        log.info("修改员工:{}", emp);
        empService.update(emp);
        return Result.success();
    }

service层:

  void update(Emp emp);

service层实现类:

 @Override
    public void update(Emp emp) {
        emp.setUpdateTime(LocalDateTime.now());
        empMapper.update(emp);    }

mapper层:

 //更新员工
    void update(Emp emp);

mapper映射文件动态SQL:

   <!--修改员工信息-->
    <update id="update">
        update emp
        <set>
            <if test="username!=null and username!=''">
                username=#{username},
            </if>
            <if test="name!=null and name!=''">
                name=#{name},
            </if>
            <if test="gender!=null">
                gender=#{gender},
            </if>
            <if test="image!=null and image!=''">
                image=#{image},
            </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>

前后端联调:

 11.配置文件

(1)参数配置化

(2)yml配置文件

#数据库连接信息
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/tlias
    username: root
    password: 123456
  servlet:
    multipart:
      max-request-size: 10MB
      max-file-size: 100MB
#mybatis配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    camel-case-to-lower-case-mapper: true

(3)@ConfigurationProperties 

12.登录校验

(1)登录

controller层: 

Slf4j
@RestController
public class LoginController {
    @Autowired
    private EmpService empService;
    @PostMapping("/login")
    public Result login(@RequestBody Emp emp){
        log.info("登录请求:{}",emp);
        Emp e = empService.login(emp);
        return e != null ? Result.success() : Result.error("用户名或密码错误");
    }
}

service层:

 Emp login(Emp emp);

 service层实现类:

 @Override
    public Emp login(Emp emp) {
        return empMapper.getByUsernameAndPassword(emp);
    }

mapper层:

 //根据用户名和密码查询员工
    @Select("select * from emp where username = #{username} and password = #{password}")
    Emp getByUsernameAndPassword(Emp emp);

(2)会话技术

 (3)JWT令牌

全称:JSON Web Token (IWT)
定义了一种简洁的、自包含的格式,用于在通信双方以ison数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的,。

组成:
第一部分:Header(头),记录令牌类型、签名算法等。例如:{"alg":"HS256","type":"JWT"}
第二部分:Pavload(有效载荷),携带一些自定义信息、默认信息等。例如:!"id":"1""username":"Tom"
第三部分:signature(签名),防止Token被篡改、确保安全性。将header、pavload,并加入指定秘钥,通过指定签名算法计算而来。        

JWT工具类: 

package com.faw.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.util.Date;
import java.util.Map;

public class JwtUtils {
    // 与测试类一致的密钥(Base64编码后的"fawvw-iot")
    private static final String SECRET_KEY = "ZmF3dnctaW90";
    // 12小时过期时间(毫秒)
    private static final long EXPIRATION = 12 * 3600 * 1000;

    /**
     * 生成JWT令牌
     * @param claims 载荷声明
     * @return JWT令牌字符串
     */
    public static String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION))
                .signWith(SignatureAlgorithm.HS256, SECRET_KEY)
                .compact();
    }

    /**
     * 解析JWT令牌
     * @param token JWT令牌
     * @return 解析后的声明体
     */
    public static Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(SECRET_KEY)
                .parseClaimsJws(token)
                .getBody();
    }
}

LoginController: 

package com.faw.controller;

import com.faw.pojo.Emp;
import com.faw.pojo.Result;
import com.faw.service.EmpService;
import com.faw.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
public class LoginController {
    @Autowired
    private EmpService empService;
    @PostMapping("/login")
    public Result login(@RequestBody Emp emp){
        log.info("登录请求:{}",emp);
        Emp e = empService.login(emp);
        if (e != null){
            //登陆成功,生成JWT
            Map<String, Object> claims = new HashMap<>();
            claims.put("id",e.getId());
            claims.put("username",e.getUsername());
            String jwt = JwtUtils.generateToken(claims);
            return Result.success(jwt);
        }
        //登录失败
        return Result.error("用户名或密码错误");
    }
}

(4)过滤器Filter

(5)拦截器Intetor

拦截路径:

定义拦截器:

package com.faw.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.faw.pojo.Result;
import com.faw.utils.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {

    @Override//目标资源方法运行前运行,返回true放行,返回false拦截
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       //1.获取url
        String url = request.getRequestURI();
        log.info("拦截的url是{}",url);
        //2.判断是否是登录操作
        if(url.contains("login")){
            //放行
            return true;
        }
        //3.获取令牌
        String jwt = request.getHeader("token");
        //4.判断令牌是否为空,如果为空,拦截,否则放行
        if(jwt==null || jwt.equals("")){
            //拦截
            log.info("token不存在,返回错误信息");
            Result error = Result.error("NOT_LOGIN");
            //返回未登录的错误信息
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(error);
            // 设置响应类型并写入响应流
            response.setContentType("application/json");
            response.getWriter().write(json);
            return false;
        }
        //5.解析token,如果解析失败,拦截,否则放行
        try {
            JwtUtils.parseToken(jwt);
        }catch (Exception e){
            //拦截
            log.info("解析令牌失败,返回未登录的错误信息");
            Result error = Result.error("NOT_LOGIN");
            //返回未登录的错误信息
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(error);
            // 设置响应类型并写入响应流
            response.setContentType("application/json");
            response.getWriter().write(json);
            return false;
        }
        //6.放行
        log.info("合法放行");
        return true;

    }

    @Override//目标资源方法运行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }


    @Override//视图渲染完成后运行,最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

注册拦截器:

package com.faw.config;

import com.faw.interceptor.LoginCheckInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/login");
    }
}

(6)异常处理

定义全局异常处理器类,类上增加@RestControllerAdvice 注解,方法上增加@ExceptionHandler注解。

@RestControllerAdvice
public class GlobalExceptionHandler {
    @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、付费专栏及课程。

余额充值