JavaWeb_SpringBootWeb案例

news2024/11/25 11:53:29

环境搭建:

开发规范

接口风格-Restful:

统一响应结果-Result:

开发流程:

        第一步应该根据需求定义表结构和定义接口文档

注意:

        本文代码从上往下一直添加功能,后面的模块下的代码包括前面的模块,并不是某个模块中的代码只有当前功能。

部门管理

查询部门:

思路:

代码:
Dept实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
    private int id;
    private String name;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}
Controller层:
@Slf4j
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    @GetMapping("/depts")
    public Result list() {
        log.info("查询全部部门信息");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

}

        (注解@Slf4j后可以直接使用log.info输出日志信息)

Service层:
接口:
public interface DeptService {

    List<Dept> list();

}
实现类:
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }
}
Mapper层:
@Mapper
public interface DeptMapper {

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

}

Postman测试结果:

删除部门:

思路:

代码:
Controller层:
@Slf4j
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**
     * 查询部门数据
     * @return
     */
    @GetMapping("/depts")
    public Result list() {
        log.info("查询全部部门信息");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    /**
     * 删除部门
     * @return
     */
    @DeleteMapping("/depts/{id}")
    public Result delete(@PathVariable Integer id) {
        log.info("删除id为" + id +"的部门");
        deptService.delete(id);
        return Result.success();
    }

}
Service层:
接口:
public interface DeptService {

    /**
     * 查询部门信息
     * @return
     */
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    void delete(Integer id);

}
实现类:
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    /**
     * 查询部门信息
     * @return
     */
    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }

    /**
     * 根据id删除部门
     * @param id
     */
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
    }
}
Mapper层:
@Mapper
public interface DeptMapper {

    /**
     * 查询部门信息
     * @return
     */
    @Select("select * from dept")
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    @Delete("delete from dept where id = #{id}")
    void deleteById(Integer id);
}

Postman测试结果:

新增部门:

思路:

代码:
Controller层:
@Slf4j
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**
     * 查询部门数据
     * @return
     */
    @GetMapping("/depts")
    public Result list() {
        log.info("查询全部部门信息");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    /**
     * 删除部门
     * @return
     */
    @DeleteMapping("/depts/{id}")
    public Result delete(@PathVariable Integer id) {
        log.info("删除id为" + id +"的部门");
        deptService.delete(id);
        return Result.success();
    }

    /**
     * 新增部门
     * @param dept
     * @return
     */
    @PostMapping("/depts")
    public Result insert(@RequestBody Dept dept) {
        log.info("添加部门:" + dept);
        deptService.add(dept);
        return Result.success();
    }

}
Service层:
接口:
public interface DeptService {

    /**
     * 查询部门信息
     * @return
     */
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    void delete(Integer id);

    /**
     * 新增部门
     * @param dept
     */
    void add(Dept dept);
}
实现类:
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    /**
     * 查询部门信息
     * @return
     */
    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }

    /**
     * 根据id删除部门
     * @param id
     */
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
    }

    /**
     * 新增部门
     * @param dept
     */
    @Override
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }
}
Mapper层:
@Mapper
public interface DeptMapper {

    /**
     * 查询部门信息
     * @return
     */
    @Select("select * from dept")
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    @Delete("delete from dept where id = #{id}")
    void deleteById(Integer id);

    /**
     * 新增部门
     * @param dept
     */
    @Insert("insert into dept(name,create_time,update_time) values (#{name},#{createTime}, #{updateTime})")
    void insert(Dept dept);
}

Postman测试结果:

优化代码:

Controller层优化:

        路径中/depts每次都出现,可以将它提取出来

优化后代码:
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**
     * 查询部门数据
     * @return
     */
    @GetMapping
    public Result list() {
        log.info("查询全部部门信息");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    /**
     * 删除部门
     * @return
     */
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        log.info("删除id为" + id +"的部门");
        deptService.delete(id);
        return Result.success();
    }

    /**
     * 新增部门
     * @param dept
     * @return
     */
    @PostMapping
    public Result insert(@RequestBody Dept dept) {
        log.info("添加部门:" + dept);
        deptService.add(dept);
        return Result.success();
    }

}

根据id查找部门:

代码:
Controller层:
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**
     * 查询部门数据
     * @return
     */
    @GetMapping
    public Result list() {
        log.info("查询全部部门信息");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    /**
     * 删除部门
     * @return
     */
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        log.info("删除id为" + id +"的部门");
        deptService.delete(id);
        return Result.success();
    }

    /**
     * 新增部门
     * @param dept
     * @return
     */
    @PostMapping
    public Result insert(@RequestBody Dept dept) {
        log.info("添加部门:" + dept);
        deptService.add(dept);
        return Result.success();
    }

    /**
     * 根据id查找部门
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("查询id为"+ id + "的部门信息");
        Dept dept = deptService.get(id);
        return Result.success(dept);
    }

}
Service层:
接口:
public interface DeptService {

    /**
     * 查询部门信息
     * @return
     */
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    void delete(Integer id);

    /**
     * 新增部门
     * @param dept
     */
    void add(Dept dept);

    /**
     * 根据id查找部门
     * @param id
     */
    Dept get(Integer id);
}
实现类:
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    /**
     * 查询部门信息
     * @return
     */
    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }

    /**
     * 根据id删除部门
     * @param id
     */
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
    }

    /**
     * 新增部门
     * @param dept
     */
    @Override
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }

    /**
     * 根据id查找部门
     * @param id
     */
    @Override
    public Dept get(Integer id) {
        return deptMapper.getById(id);
    }
}
Mapper层:
@Mapper
public interface DeptMapper {

    /**
     * 查询部门信息
     * @return
     */
    @Select("select * from dept")
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    @Delete("delete from dept where id = #{id}")
    void deleteById(Integer id);

    /**
     * 新增部门
     * @param dept
     */
    @Insert("insert into dept(name,create_time,update_time) values (#{name},#{createTime}, #{updateTime})")
    void insert(Dept dept);

    /**
     * 根据id查找部门
     * @param id
     * @return
     */
    @Select("select * from dept where id = #{id}")
    Dept getById(Integer id);
}

Postman测试结果:

修改部门:

代码:
Controller层:
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**
     * 查询部门数据
     * @return
     */
    @GetMapping
    public Result list() {
        log.info("查询全部部门信息");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    /**
     * 删除部门
     * @return
     */
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        log.info("删除id为" + id +"的部门");
        deptService.delete(id);
        return Result.success();
    }

    /**
     * 新增部门
     * @param dept
     * @return
     */
    @PostMapping
    public Result insert(@RequestBody Dept dept) {
        log.info("添加部门:" + dept);
        deptService.add(dept);
        return Result.success();
    }

    /**
     * 根据id查找部门
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("查询id为"+ id + "的部门信息");
        Dept dept = deptService.get(id);
        return Result.success(dept);
    }

    /**
     * 修改部门
     * @param dept
     * @return
     */
    @PutMapping
    public Result update(@RequestBody Dept dept) {
        log.info("修改部门:" + dept);
        deptService.update(dept);
        return Result.success();
    }

}
Service层:
接口:
public interface DeptService {

    /**
     * 查询部门信息
     * @return
     */
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    void delete(Integer id);

    /**
     * 新增部门
     * @param dept
     */
    void add(Dept dept);

    /**
     * 根据id查找部门
     * @param id
     */
    Dept get(Integer id);

    /**
     * 修改部门
     * @param dept
     */
    void update(Dept dept);
}
实现类:
@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    /**
     * 查询部门信息
     * @return
     */
    @Override
    public List<Dept> list() {
        return deptMapper.list();
    }

    /**
     * 根据id删除部门
     * @param id
     */
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
    }

    /**
     * 新增部门
     * @param dept
     */
    @Override
    public void add(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }

    /**
     * 根据id查找部门
     * @param id
     */
    @Override
    public Dept get(Integer id) {
        return deptMapper.getById(id);
    }

    /**
     * 修改部门
     * @param dept
     */
    @Override
    public void update(Dept dept) {
        dept.setCreateTime(LocalDateTime.now());
        dept.setUpdateTime(LocalDateTime.now());
        deptMapper.update(dept);
    }
}
Mapper层:
@Mapper
public interface DeptMapper {

    /**
     * 查询部门信息
     * @return
     */
    @Select("select * from dept")
    List<Dept> list();

    /**
     * 根据id删除部门
     * @param id
     */
    @Delete("delete from dept where id = #{id}")
    void deleteById(Integer id);

    /**
     * 新增部门
     * @param dept
     */
    @Insert("insert into dept(name,create_time,update_time) values (#{name},#{createTime}, #{updateTime})")
    void insert(Dept dept);

    /**
     * 根据id查找部门
     * @param id
     * @return
     */
    @Select("select * from dept where id = #{id}")
    Dept getById(Integer id);

    /**
     * 修改部门
     * @param dept
     */
    @Update("update dept set name = #{name},create_time = #{createTime},update_time = #{updateTime} where id = #{id}")
    void update(Dept dept);
}

Postman测试结果:

员工管理:

分页查询:

思路:

 代码:

Emp实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Short gender;
    private String image;
    private Short job;
    private LocalDate entryDate;
    private Integer deptId;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}
Controller层:
@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    @GetMapping
    public Result getPage(@RequestParam(defaultValue = "1") Integer page,
                          @RequestParam(defaultValue = "10") Integer pageSize) {
        log.info("每页记录数:{},查询页码:{}",pageSize,page);
        PageBean pb = empService.getPage(page,pageSize);
        return Result.success(pb);
    }

}
Service层:
接口:
public interface EmpService {
    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    PageBean getPage(Integer page, Integer pageSize);

}
实现类:
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

    /**
     * 分页查询,获取列表数据
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageBean getPage(Integer page, Integer pageSize) {
        Long total = empMapper.getTotal();
        Long start = (long) ((page - 1) * pageSize);
        List<Emp> rows = empMapper.getRows(start,pageSize);
        PageBean pageBean = new PageBean(total,rows);
        return pageBean;
    }
}
Mapper层:
@Mapper
public interface EmpMapper {

    /**
     * 获取总记录数
     * @return
     */
    @Select("select count(*) from emp;")
    Long getTotal();

    /**
     * 分页查询,获取列表数据
     * @param start
     * @param pageSize
     * @return
     */
    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n" +
            "from emp limit #{start},#{pageSize}")
    List<Emp> getRows(Long start, Integer pageSize);


    
}

Postman测试结果:

分页插件-PageHelper:

        由下图可以看到原始方式分页查询步骤固定,而且代码繁琐,我们可以使用PageHelper插件简化代码。

代码演示:
导入依赖:
<!--PageHelper分页插件-->
		<dependency>
			<groupId>com.github.pagehelper</groupId>
			<artifactId>pagehelper-spring-boot-starter</artifactId>
			<version>1.4.6</version>
		</dependency>
修改代码:
Mapper层:
@Mapper
public interface EmpMapper {
//    /**
//     * 获取总记录数
//     * @return
//     */
//    @Select("select count(*) from emp")
//    Long getTotal();
//
//    /**
//     * 分页查询,获取列表数据
//     * @param start
//     * @param pageSize
//     * @return
//     */
//    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n" +
//            "from emp limit #{start},#{pageSize}")
//    List<Emp> getRows(Long start, Integer pageSize);

    /**
     * 使用PageHelper插件来进行分页查询
     */
    @Select("select * from emp")
    List<Emp> list();

    
}
Service层:
实现类:
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

//    /**
//     * 分页查询,获取列表数据
//     * @param page
//     * @param pageSize
//     * @return
//     */
//    @Override
//    public PageBean getPage(Integer page, Integer pageSize) {
//        Long total = empMapper.getTotal();
//        Long start = (long) ((page - 1) * pageSize);
//        List<Emp> rows = empMapper.getRows(start,pageSize);
//        PageBean pageBean = new PageBean(total,rows);
//        return pageBean;
//    }

    /**
     * 使用PageHelper分页插件进行分页查询
     */
    @Override
    public PageBean getPage(Integer page, Integer pageSize) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.执行查询
        List<Emp> empList = empMapper.list();
        Page<Emp> p = (Page<Emp>) empList;
        //3.封装PageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }

}

分页条件查询:

措施:

代码:
 Controller层:
@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    @GetMapping
    public Result getPage(@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("每页记录数:{},查询页码:{}",pageSize,page);
        PageBean pb = empService.getPage(page,pageSize,name,gender,begin,end);
        return Result.success(pb);
    }

}
Service层:
接口:
public interface EmpService {
    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);

}
实现类:
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

//    /**
//     * 分页查询,获取列表数据
//     * @param page
//     * @param pageSize
//     * @return
//     */
//    @Override
//    public PageBean getPage(Integer page, Integer pageSize) {
//        Long total = empMapper.getTotal();
//        Long start = (long) ((page - 1) * pageSize);
//        List<Emp> rows = empMapper.getRows(start,pageSize);
//        PageBean pageBean = new PageBean(total,rows);
//        return pageBean;
//    }

    /**
     * 使用PageHelper分页插件进行分页查询
     */
    @Override
    public PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.执行查询
        List<Emp> empList = empMapper.list(name,gender,begin,end);
        Page<Emp> p = (Page<Emp>) empList;
        //3.封装PageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }

}
Mapper层:
@Mapper
public interface EmpMapper {
//    /**
//     * 获取总记录数
//     * @return
//     */
//    @Select("select count(*) from emp")
//    Long getTotal();
//
//    /**
//     * 分页查询,获取列表数据
//     * @param start
//     * @param pageSize
//     * @return
//     */
//    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n" +
//            "from emp limit #{start},#{pageSize}")
//    List<Emp> getRows(Long start, Integer pageSize);

    /**
     * 使用PageHelper插件来进行分页查询
     */
    //动态SQL
    List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

    
}
动态SQL:
xml文件:
<?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.han.mapper.EmpMapper">
    <select id="list" resultType="com.han.pojo.Emp">
        select id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_time
        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>

Postman测试结果:

删除员工:

代码:
 Controller层:
@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    @GetMapping
    public Result getPage(@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("每页记录数:{},查询页码:{}",pageSize,page);
        PageBean pb = empService.getPage(page,pageSize,name,gender,begin,end);
        return Result.success(pb);
    }

    /**
     * 批量删除员工
     * @param ids
     * @return
     */
    @DeleteMapping("/{ids}")
    public Result delete(@PathVariable("ids") List<Short> ids) {
        log.info("批量删除操作ids:{}",ids);
        empService.delete(ids);
        return Result.success();
    }

}
Service层:
接口:
public interface EmpService {
    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);
}
实现类:
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

//    /**
//     * 分页查询,获取列表数据
//     * @param page
//     * @param pageSize
//     * @return
//     */
//    @Override
//    public PageBean getPage(Integer page, Integer pageSize) {
//        Long total = empMapper.getTotal();
//        Long start = (long) ((page - 1) * pageSize);
//        List<Emp> rows = empMapper.getRows(start,pageSize);
//        PageBean pageBean = new PageBean(total,rows);
//        return pageBean;
//    }

    /**
     * 使用PageHelper分页插件进行分页查询
     */
    @Override
    public PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.执行查询
        List<Emp> empList = empMapper.list(name,gender,begin,end);
        Page<Emp> p = (Page<Emp>) empList;
        //3.封装PageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }

    /**
     * 批量删除员工
     * @param ids
     */
    @Override
    public void delete(List<Short> ids) {
        empMapper.delete(ids);
    }

}
Mapper层:
@Mapper
public interface EmpMapper {
//    /**
//     * 获取总记录数
//     * @return
//     */
//    @Select("select count(*) from emp")
//    Long getTotal();
//
//    /**
//     * 分页查询,获取列表数据
//     * @param start
//     * @param pageSize
//     * @return
//     */
//    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n" +
//            "from emp limit #{start},#{pageSize}")
//    List<Emp> getRows(Long start, Integer pageSize);

    //动态SQL
    /**
     * 使用PageHelper插件来进行分页查询
     */

    List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);

}
动态SQL:
xml文件:
<?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.han.mapper.EmpMapper">
    <select id="list" resultType="com.han.pojo.Emp">
        select id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_time
        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>

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

</mapper>

Postman测试结果:

文件上传:

本地存储(不推荐):

        使用MultipartFile类型接收文件,再使用下面的方法

阿里云OSS存储(推荐):

        用户上文中图像的上传

代码演示:
工具类:
/**
 * 阿里云 OSS 工具类
 */
@RestController
public class AliOSSUtils {

    /**
     * 实现上传图片到OSS
     */
    public String upload(MultipartFile file) throws ClientException, IOException {

        InputStream inputStream = file.getInputStream();

        // 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-beijing.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "web-talias-test";
        // 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = file.getOriginalFilename();

        String fileName = UUID.randomUUID().toString() + objectName.substring(objectName.lastIndexOf("."));
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。

        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);


        // 创建PutObjectRequest对象。
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
        // 上传文件。
        PutObjectResult result = ossClient.putObject(putObjectRequest);


        // 设置请求头。
        Map<String, String> headers = new HashMap<String, String>();
        /*// 指定Object的存储类型。
        headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
        // 指定ContentType。
        headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/

        // 设置用户自定义元数据。
        Map<String, String> userMetadata = new HashMap<String, String>();
        /*userMetadata.put("key1","value1");
        userMetadata.put("key2","value2");*/

        URL signedUrl = null;
        // 指定生成的签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
        Date expiration = new Date(new Date().getTime() + 3600 * 1000L);

        // 生成签名URL。
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, fileName);
        // 设置过期时间。
        request.setExpiration(expiration);

        // 将请求头加入到request中。
        request.setHeaders(headers);
        // 添加用户自定义元数据。
        request.setUserMetadata(userMetadata);

        // 通过HTTP PUT请求生成签名URL。
        signedUrl = ossClient.generatePresignedUrl(request);
        // 返回签名URL。
        ossClient.shutdown();
        return signedUrl.toString().split("\\?")[0];
    }

}
文件上传Controller层:
@Slf4j
@RestController
public class UploadController {

    @Autowired
    private AliOSSUtils aliOSSUtils;

    @PostMapping("/upload")
    public Result upload(MultipartFile image) throws IOException, ClientException {

        log.info("接收到文件:{}",image.getOriginalFilename());
        String url = aliOSSUtils.upload(image);
        log.info("已将文件存储到阿里云OSS,url:{}",url);
        return Result.success(url);

    }

}

修改员工

1.查询回显:

 代码:

 Controller层:
@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    @GetMapping
    public Result getPage(@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("每页记录数:{},查询页码:{}",pageSize,page);
        PageBean pb = empService.getPage(page,pageSize,name,gender,begin,end);
        return Result.success(pb);
    }

    /**
     * 批量删除员工
     * @param ids
     * @return
     */
    @DeleteMapping("/{ids}")
    public Result delete(@PathVariable("ids") List<Short> ids) {
        log.info("批量删除操作ids:{}",ids);
        empService.delete(ids);
        return Result.success();
    }

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

    /**
     * 根据id查询员工
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("查询id为:{}的员工",id);
        Emp emp = empService.getById(id);
        return Result.success(emp);
    }


}
Service层:
接口:
public interface EmpService {
    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);

    /**
     * 新增员工
     * @param emp
     */
    void add(Emp emp);

    /**
     * 根据id查询员工
     * @return
     */
    Emp getById(Integer id);
}
实现类:
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

//    /**
//     * 分页查询,获取列表数据
//     * @param page
//     * @param pageSize
//     * @return
//     */
//    @Override
//    public PageBean getPage(Integer page, Integer pageSize) {
//        Long total = empMapper.getTotal();
//        Long start = (long) ((page - 1) * pageSize);
//        List<Emp> rows = empMapper.getRows(start,pageSize);
//        PageBean pageBean = new PageBean(total,rows);
//        return pageBean;
//    }

    /**
     * 使用PageHelper分页插件进行分页查询
     */
    @Override
    public PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.执行查询
        List<Emp> empList = empMapper.list(name,gender,begin,end);
        Page<Emp> p = (Page<Emp>) empList;
        //3.封装PageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }

    /**
     * 批量删除员工
     * @param ids
     */
    @Override
    public void delete(List<Short> ids) {
        empMapper.delete(ids);
    }

    /**
     * 新增员工
     * @param emp
     */
    @Override
    public void add(Emp emp) {
        emp.setUpdateTime(LocalDateTime.now());
        emp.setCreateTime(LocalDateTime.now());
        empMapper.add(emp);
    }

    /**
     * 根据id查询员工
     * @return
     */
    @Override
    public Emp getById(Integer id) {
        Emp emp = empMapper.get(id);
        return emp;
    }

}
Mapper层:
@Mapper
public interface EmpMapper {
//    /**
//     * 获取总记录数
//     * @return
//     */
//    @Select("select count(*) from emp")
//    Long getTotal();
//
//    /**
//     * 分页查询,获取列表数据
//     * @param start
//     * @param pageSize
//     * @return
//     */
//    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n" +
//            "from emp limit #{start},#{pageSize}")
//    List<Emp> getRows(Long start, Integer pageSize);

    //动态SQL
    /**
     * 使用PageHelper插件来进行分页查询
     */

    List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);

    /**
     * 新增员工
     * @param emp
     */
    @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 add(Emp emp);

    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time " +
            "from emp where id = #{id}")
    Emp get(Integer id);
}
Postman测试结果:

2.修改员工:

 代码:

 Controller层:
@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    @GetMapping
    public Result getPage(@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("每页记录数:{},查询页码:{}",pageSize,page);
        PageBean pb = empService.getPage(page,pageSize,name,gender,begin,end);
        return Result.success(pb);
    }

    /**
     * 批量删除员工
     * @param ids
     * @return
     */
    @DeleteMapping("/{ids}")
    public Result delete(@PathVariable("ids") List<Short> ids) {
        log.info("批量删除操作ids:{}",ids);
        empService.delete(ids);
        return Result.success();
    }

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

    /**
     * 根据id查询员工
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("查询id为:{}的员工",id);
        Emp emp = empService.getById(id);
        return Result.success(emp);
    }

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

}
Service层:
接口:
public interface EmpService {
    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);

    /**
     * 新增员工
     * @param emp
     */
    void add(Emp emp);

    /**
     * 根据id查询员工
     * @return
     */
    Emp getById(Integer id);

    void update(Emp emp);
}
实现类:
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

//    /**
//     * 分页查询,获取列表数据
//     * @param page
//     * @param pageSize
//     * @return
//     */
//    @Override
//    public PageBean getPage(Integer page, Integer pageSize) {
//        Long total = empMapper.getTotal();
//        Long start = (long) ((page - 1) * pageSize);
//        List<Emp> rows = empMapper.getRows(start,pageSize);
//        PageBean pageBean = new PageBean(total,rows);
//        return pageBean;
//    }

    /**
     * 使用PageHelper分页插件进行分页查询
     */
    @Override
    public PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.执行查询
        List<Emp> empList = empMapper.list(name,gender,begin,end);
        Page<Emp> p = (Page<Emp>) empList;
        //3.封装PageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }

    /**
     * 批量删除员工
     * @param ids
     */
    @Override
    public void delete(List<Short> ids) {
        empMapper.delete(ids);
    }

    /**
     * 新增员工
     * @param emp
     */
    @Override
    public void add(Emp emp) {
        emp.setUpdateTime(LocalDateTime.now());
        emp.setCreateTime(LocalDateTime.now());
        empMapper.add(emp);
    }

    /**
     * 根据id查询员工
     * @return
     */
    @Override
    public Emp getById(Integer id) {
        Emp emp = empMapper.get(id);
        return emp;
    }

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

}
Mapper层:
@Mapper
public interface EmpMapper {
//    /**
//     * 获取总记录数
//     * @return
//     */
//    @Select("select count(*) from emp")
//    Long getTotal();
//
//    /**
//     * 分页查询,获取列表数据
//     * @param start
//     * @param pageSize
//     * @return
//     */
//    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n" +
//            "from emp limit #{start},#{pageSize}")
//    List<Emp> getRows(Long start, Integer pageSize);

    //动态SQL
    /**
     * 使用PageHelper插件来进行分页查询
     */

    List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);

    /**
     * 新增员工
     * @param emp
     */
    @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 add(Emp emp);

    /**
     * 根据id查询员工
     * @param id
     * @return
     */
    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time " +
            "from emp where id = #{id}")
    Emp get(Integer id);

    /**
     * 修改员工
     * @param emp
     */
    void update(Emp emp);
}
动态SQL:
xml文件:
<?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.han.mapper.EmpMapper">
    <select id="list" resultType="com.han.pojo.Emp">
        select id,username,password,name,gender,image,job,entrydate,dept_id,create_time,update_time
        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>

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

    <update id="update">
        update emp
        <set>
            <if test="image != null and image !=''">
                image = #{image},
            </if>
            <if test="username != null and image !=''">
                username = #{username},
            </if>
            <if test="name != null and image !=''">
                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>
                update_time = #{updateTime}
        </set>
        where id = #{id}
    </update>

</mapper>
Postman测试结果:

配置文件:

1.参数配置化

        因为将文件上传阿里云OSS,总是需要endpoint和bucketName,但是这些还是固定的,所以直接将它们存储在配置文件中

代码演示:
配置文件applicat-properties:
#自定义的阿里云OSS配置信息
aliyun.oss.endpoint=https://oss-cn-beijing.aliyuncs.com
aliyun.oss.bucketName=web-talias-test
工具类:
/**
 * 阿里云 OSS 工具类
 */
@RestController
public class AliOSSUtils {

    // 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
    @Value("${aliyun.oss.endpoint}")
    private String endpoint;
    // 填写Bucket名称,例如examplebucket。
    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    /**
     * 实现上传图片到OSS
     */
    public String upload(MultipartFile file) throws ClientException, IOException {

        InputStream inputStream = file.getInputStream();

        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = file.getOriginalFilename();

        String fileName = UUID.randomUUID().toString() + objectName.substring(objectName.lastIndexOf("."));
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。

        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);


        // 创建PutObjectRequest对象。
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
        // 上传文件。
        PutObjectResult result = ossClient.putObject(putObjectRequest);


        // 设置请求头。
        Map<String, String> headers = new HashMap<String, String>();
        /*// 指定Object的存储类型。
        headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
        // 指定ContentType。
        headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/

        // 设置用户自定义元数据。
        Map<String, String> userMetadata = new HashMap<String, String>();
        /*userMetadata.put("key1","value1");
        userMetadata.put("key2","value2");*/

        URL signedUrl = null;
        // 指定生成的签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
        Date expiration = new Date(new Date().getTime() + 3600 * 1000L);

        // 生成签名URL。
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, fileName);
        // 设置过期时间。
        request.setExpiration(expiration);

        // 将请求头加入到request中。
        request.setHeaders(headers);
        // 添加用户自定义元数据。
        request.setUserMetadata(userMetadata);

        // 通过HTTP PUT请求生成签名URL。
        signedUrl = ossClient.generatePresignedUrl(request);
        // 返回签名URL。
        ossClient.shutdown();
        return signedUrl.toString().split("\\?")[0];
    }

}

2.(推荐)yml(yaml)配置文件:

常见配置文件格式对比:

yml基本语法:

数据格式:

代码演示:

        将下面application.properties文件改写成application.yml文件

application.properties:
spring.application.name=tlias
#驱动器名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/tlias
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456

#配置mybatis的日志,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#开启mybatis的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true

#自定义的阿里云OSS配置信息
aliyun.oss.endpoint=https://oss-cn-beijing.aliyuncs.com
aliyun.oss.bucketName=web-talias-test
application.yml:
spring:
  application:
    name: tlias
  #数据库连接信息
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/tlias
    username: root
    password: 123456
  #文件上传的配置
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 100MB
#mybatis配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true

#阿里云OSS配置
aliyun:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    bucketName: web-talias-test

3.ConfigurationProperties

与@Value的区别:

应用场景:

        如果需要注解的属性只有一两个,而且只需要注解一次,那么使用@Value注解,如果需要注解的属性较多,而且需要多次注解,就使用@ConfigurationProperties注解。

代码演示:
AliOSSProperties:
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
public class AliOSSProperties {
    private String endpoint;
    private String bucketName;
}
AliOSSUtils:
/**
 * 阿里云 OSS 工具类
 */
@RestController
public class AliOSSUtils {

//    // 以华东1(杭州)的外网Endpoint为例,其它Region请按实际情况填写。
//    @Value("${aliyun.oss.endpoint}")
//    private String endpoint;
//    // 填写Bucket名称,例如examplebucket。
//    @Value("${aliyun.oss.bucketName}")
//    private String bucketName;

    @Autowired
    private AliOSSProperties aliOSSProperties;

    /**
     * 实现上传图片到OSS
     */
    public String upload(MultipartFile file) throws ClientException, IOException {

        String endpoint = aliOSSProperties.getEndpoint();
        String bucketName = aliOSSProperties.getBucketName();

        InputStream inputStream = file.getInputStream();

        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = file.getOriginalFilename();

        String fileName = UUID.randomUUID().toString() + objectName.substring(objectName.lastIndexOf("."));
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。

        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);


        // 创建PutObjectRequest对象。
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
        // 上传文件。
        PutObjectResult result = ossClient.putObject(putObjectRequest);


        // 设置请求头。
        Map<String, String> headers = new HashMap<String, String>();
        /*// 指定Object的存储类型。
        headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
        // 指定ContentType。
        headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/

        // 设置用户自定义元数据。
        Map<String, String> userMetadata = new HashMap<String, String>();
        /*userMetadata.put("key1","value1");
        userMetadata.put("key2","value2");*/

        URL signedUrl = null;
        // 指定生成的签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
        Date expiration = new Date(new Date().getTime() + 3600 * 1000L);

        // 生成签名URL。
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, fileName);
        // 设置过期时间。
        request.setExpiration(expiration);

        // 将请求头加入到request中。
        request.setHeaders(headers);
        // 添加用户自定义元数据。
        request.setUserMetadata(userMetadata);

        // 通过HTTP PUT请求生成签名URL。
        signedUrl = ossClient.generatePresignedUrl(request);
        // 返回签名URL。
        ossClient.shutdown();
        return signedUrl.toString().split("\\?")[0];
    }

}

登录功能:

基础登录功能代码:

 Controller层:

@Slf4j
@RestController
public class LoginController {

    @Autowired
    EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {

        log.info("用户尝试登录,登录信息:{}",emp);
        Boolean result = empService.login(emp);
        /*if(result){
            return Result.success();
        } else {
            return Result.error("用户名或密码错误!");
        }*/
        return result == true ? Result.success() : Result.error("用户名或密码错误!");

    }

}

Service层:

接口:
public interface EmpService {
    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);

    /**
     * 新增员工
     * @param emp
     */
    void add(Emp emp);

    /**
     * 根据id查询员工
     * @return
     */
    Emp getById(Integer id);

    void update(Emp emp);

    Boolean login(Emp emp);
}
实现类:
@Service
public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpMapper empMapper;

//    /**
//     * 分页查询,获取列表数据
//     * @param page
//     * @param pageSize
//     * @return
//     */
//    @Override
//    public PageBean getPage(Integer page, Integer pageSize) {
//        Long total = empMapper.getTotal();
//        Long start = (long) ((page - 1) * pageSize);
//        List<Emp> rows = empMapper.getRows(start,pageSize);
//        PageBean pageBean = new PageBean(total,rows);
//        return pageBean;
//    }

    /**
     * 使用PageHelper分页插件进行分页查询
     */
    @Override
    public PageBean getPage(Integer page, Integer pageSize, String name, Short gender, LocalDate begin, LocalDate end) {
        //1.设置分页参数
        PageHelper.startPage(page, pageSize);
        //2.执行查询
        List<Emp> empList = empMapper.list(name,gender,begin,end);
        Page<Emp> p = (Page<Emp>) empList;
        //3.封装PageBean对象
        PageBean pageBean = new PageBean(p.getTotal(),p.getResult());
        return pageBean;
    }

    /**
     * 批量删除员工
     * @param ids
     */
    @Override
    public void delete(List<Short> ids) {
        empMapper.delete(ids);
    }

    /**
     * 新增员工
     * @param emp
     */
    @Override
    public void add(Emp emp) {
        emp.setUpdateTime(LocalDateTime.now());
        emp.setCreateTime(LocalDateTime.now());
        empMapper.add(emp);
    }

    /**
     * 根据id查询员工
     * @return
     */
    @Override
    public Emp getById(Integer id) {
        Emp emp = empMapper.get(id);
        return emp;
    }

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

    @Override
    public Boolean login(Emp emp) {
        Short count = empMapper.getByUsernameAndPassword(emp);
        if(count == 1){
            return true;
        } else {
            return false;
        }
    }

}

Mapper层:

@Mapper
public interface EmpMapper {
//    /**
//     * 获取总记录数
//     * @return
//     */
//    @Select("select count(*) from emp")
//    Long getTotal();
//
//    /**
//     * 分页查询,获取列表数据
//     * @param start
//     * @param pageSize
//     * @return
//     */
//    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time\n" +
//            "from emp limit #{start},#{pageSize}")
//    List<Emp> getRows(Long start, Integer pageSize);

    //动态SQL
    /**
     * 使用PageHelper插件来进行分页查询
     */

    List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);

    /**
     * 批量删除员工
     * @param ids
     */
    void delete(List<Short> ids);

    /**
     * 新增员工
     * @param emp
     */
    @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 add(Emp emp);

    /**
     * 根据id查询员工
     * @param id
     * @return
     */
    @Select("select id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time " +
            "from emp where id = #{id}")
    Emp get(Integer id);

    /**
     * 修改员工
     * @param emp
     */
    void update(Emp emp);

    @Select("select count(*) from emp where username = #{username} and password = #{password}")
    Short getByUsernameAndPassword(Emp emp);
}

Postman测试结果:

问题:

        使用上面的基础登录功能代码运行程序会有一些问题,比如直接访问接口路径浏览器会直接跳到对应的接口网址页面,而不需要登录操作。为了解决这一问题我们需要进行登录校验

登录校验:

会话技术:

会话跟踪方案:

1.Cookie:

2.Session

3★.令牌技术(推荐)

JWT令牌:

使用场景:

        最广泛的使用场景:登录认证

JWT生成:

导入依赖:

    <dependency>
		<groupId>io.jsonwebtoken</groupId>
		<artifactId>jjwt</artifactId>
		<version>0.9.1</version>
	</dependency>
代码演示:
    /**
     * 生成JWT令牌
     */
    @Test
    void testJwt() {
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", "admin");
        claims.put("password", "123456");

        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "hann")//签名算法
                .setClaims(claims)//自定义内容(载荷)
                .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期1h
                .compact();

        System.out.println(jwt);
    }

    /**
     * 解析JWT令牌
     */
    @Test
    void testParseJwt(){
        Claims claims = Jwts.parser()
                .setSigningKey("hann")//指定签名密钥
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9" +
                        ".eyJwYXNzd29yZCI6IjEyMzQ1NiIsImV4cCI6MTcxNzQwNTg3NywidXNlcm5hbWUiOiJhZG1pbiJ9" +
                        ".iup_46wg3STPq6Dffbt36IYKTbN8cwiRcOm_8uI_slY")//解析令牌
                .getBody();
        System.out.println(claims);
    }
注意事项:

        接下来通过jwt令牌进行登录校验。

改写登录功能:

思路:

1.生成JWT令牌
代码演示:

        这里我发现之前基础的登录功能只返回一个布尔类型的值,是只能获取到用户名和密码的,但是在生成JWT令牌是自定义内容写用户名和密码是可以被解码的,这样信息就不安全,所以我把登录的一系列接口和方法返回的类型改成Emp实体类了

JWT令牌工具类:
public class JwtUtils {

    private static String signKey = "hann";
    private static Long expirationTime = 43200000L;


    /**
     * 获得JWT令牌
     */
    public static String getJwt(Map<String, Object> claims) {
        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, signKey)//签名算法
                .setClaims(claims)//自定义内容(载荷)
                .setExpiration(new Date(System.currentTimeMillis() + expirationTime))//设置有效期12h
                .compact();

        return jwt;
    }



}
Controller层:
@Slf4j
@RestController
public class LoginController {

    @Autowired
    EmpService empService;

    @PostMapping("/login")
    public Result login(@RequestBody Emp emp) {


        log.info("用户尝试登录,登录信息:{}",emp);
        Emp e = empService.login(emp);
        if(e != null){
            //登录成功
            Map<String, Object> map = new HashMap<>();
            map.put("id", e.getId());
            map.put("name", e.getName());
            map.put("username", e.getUsername());
            String jwt = JwtUtils.getJwt(map);
            return Result.success(jwt);
        } else {
            return Result.error("用户名或密码错误!");
        }
    }

}
Postman测试结果:

2.统一校验JWT令牌
①过滤器Filter:

使用方法:

        注解@WebFilter中urlPatterns = "/*"表示拦截所有路径。

执行流程:

拦截路径:

过滤器链:

登录校验流程:
代码:

pom.xml:

引入依赖用于将Result对象转为JSON格式

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.76</version>
		</dependency>

Filter:

@Slf4j
@WebFilter
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        //1.获取url
        String url = req.getRequestURL().toString();

        //2.判断url中是否包含login,如果有直接放行,如果没有需要再判断
        if(url.contains("login")) {
            log.info("登录操作,放行");
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }

        //3.获取请求头中的令牌
        String jwt = req.getHeader("token");

        //4.判断令牌是否存在,若存在继续判断,不存在则返回未登录信息
        if(!StringUtils.hasLength(jwt)) {
            log.info("请求头token为空,返回未登录信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象->JSON 格式 利用阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }

        //令牌存在,判断令牌是否合法,不合法返回未登录信息
        try {
            JwtUtils.parseJwt(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("解析令牌失败,返回未登录信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象->JSON 格式 利用阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }

        //放行
        log.info("令牌合法,放行,jwt:{}",jwt);
        filterChain.doFilter(servletRequest, servletResponse);

    }
}
Postman测试:

②拦截器Interceptor:

使用方法:

拦截路径:

与过滤器Filter的区别:

代码:

Interceptor:

@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {

    @Override//目标资源方法执行前执行,返回true 放行,返回false 不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {

        //1.获取url
        String url = req.getRequestURL().toString();

        //2.判断url中是否包含login,如果有直接放行,如果没有需要再判断
        if(url.contains("login")) {
            log.info("登录操作,放行");
            return true;
        }

        //3.获取请求头中的令牌
        String jwt = req.getHeader("token");

        //4.判断令牌是否存在,若存在继续判断,不存在则返回未登录信息
        if(!StringUtils.hasLength(jwt)) {
            log.info("请求头token为空,返回未登录信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象->JSON 格式 利用阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return false;
        }

        //令牌存在,判断令牌是否合法,不合法返回未登录信息
        try {
            JwtUtils.parseJwt(jwt);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("解析令牌失败,返回未登录信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换 对象->JSON 格式 利用阿里巴巴fastJSON
            String notLogin = JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return false;
        }

        //放行
        log.info("令牌合法,放行,jwt:{}",jwt);
        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);
    }
}

配置类:

@Configuration//配置类
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    LoginCheckInterceptor loginCheckInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**").excludePathPatterns("/login");
    }


}

异常处理

全局异常处理器:

代码:
exception:
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Result ex(Exception ex) {
        ex.printStackTrace();
        return Result.error("对不起,操作失败,请联系管理员");
    }


}

       

        到这里基础功能部分基本完成,下面是上面代码的一些注意事项。

注意事项:

        1.参数及属性值都使用基本类型的包装类,比如int类型用Integer,short类型用Short,这样传递的值为空也不会报错

        2.动态SQL中,查询语句后不能加分号

        3.根据name查询时模糊匹配使用name like concat('%',#{name},'%') 字符串拼接,不然编译后#{...}变成问号出现在字符串中不起作用,并且<if>的test判断中不仅要添加非空判断,还要加上等于空值的判断and name != '',否则不输入内容点击查询会传递一个空值字符串。

事务管理:

Spring事务管理:

代码演示:
empMapper:

        添加代码

@Delete("delete from emp where dept_id = #{deptId}")
    void deleteByDeptId(Integer deptId);
DeptService:

        修改删除部门代码

    /**
     * 根据id删除部门
     * @param id
     */
    @Transactional
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
        //删除该部门下的员工
        empMapper.deleteByDeptId(id);
    }

事务属性

1.回滚rollbackFor:

        将回滚属性改为出现任何异常都回滚

代码演示:
    /**
     * 根据id删除部门
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
        //删除该部门下的员工
        empMapper.deleteByDeptId(id);
    }

2.传播行为propagation:

案例

代码:
建表SQL语句:
CREATE TABLE `dept_log` (
  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `description` varchar(300) NOT NULL COMMENT '部分解散描述',
  PRIMARY KEY (`id`)
) 
日志实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeptLog {
    private int id;
    private LocalDateTime createTime;
    private String description;
}
Controller层:

删除部门部分:

    /**
     * 根据id删除部门
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(Integer id) {
        try {
            deptMapper.deleteById(id);

            int i = 1/0;

            //删除该部门下的员工
            empMapper.deleteByDeptId(id);
        } finally {
            DeptLog deptLog = new DeptLog();
            deptLog.setCreateTime(LocalDateTime.now());
            deptLog.setDescription("删除部门,id为:" + id);
            deptLogService.insert(deptLog);
        }
    }
Service层:

接口:

public interface DeptLogService {

    void insert(DeptLog log);

}

实现类:

@Service
public class DeptLogServiceImpl implements DeptLogService {

    @Autowired
    DeptLogMapper deptLogMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void insert(DeptLog log) {
        deptLogMapper.insert(log);
    }

}
Mapper层:
@Mapper
public interface DeptLogMapper {

    @Insert("insert into dept_log(create_time,description) values (#{createTime},#{description})")
    void insert(DeptLog log);

}
使用场景:

AOP(面向切面编程)

场景:

        基于动态代理实现,最后运行的是基于目标对象代理的加强后的方法

代码:

在pom.xim文件中添加依赖:

        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

编写AOP程序:

@Slf4j
@Component
@Aspect//AOP类
public class TimeAspect {

    @Around("execution(* com.han.service.*.*(..))")
    public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
        long begin = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        log.info(joinPoint.getSignature() + "方法的执行时间为{}ms", end - begin);
        return result;
    }

}

优势:

核心概念:

通知类型:

@PointCut:

通知顺序:

切入点表达式:

1.execution:

书写建议:

2.@annotation:

        它可以通过自定义注解,然后在写切入点表达式时括号中写这个自定义注解的全类名,就可以把这个自定义注解注解的方法包含。

连接点:

案例:

准备工作:

建表:
-- 操作日志表
create table operate_log(
                            id int unsigned primary key auto_increment comment 'ID',
                            operate_user int unsigned comment '操作人ID',
                            operate_time datetime comment '操作时间',
                            class_name varchar(100) comment '操作的类名',
                            method_name varchar(100) comment '操作的方法名',
                            method_params varchar(1000) comment '方法参数',
                            return_value varchar(2000) comment '返回值',
                            cost_time bigint comment '方法执行耗时, 单位:ms'
) comment '操作日志表';
创建实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OperateLog {
    private Integer id;
    private Integer operateUser;
    private LocalDateTime operateTime;
    private String className;
    private String methodName;
    private String methodParams;
    private String returnValue;
    private Long costTime;
}

编码:

定义Mapper:
@Mapper
public interface OperateLodMapper {

    @Insert("insert into operate_log (operate_user,operate_time,class_name,method_name,method_params,return_value,cost_time)" +
            "values (#{operateUser},#{operateTime},#{className},#{methodName},#{methodParams},#{returnValue},#{costTime})")
    public void insert(OperateLog log);
}
定义注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
}
编写AOP代码:
@Slf4j
@Component
@Aspect
public class LogAspect {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private OperateLodMapper operateLodMapper;

    @Around("@annotation(com.han.anno.Log)")
    public Object recordLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //获取操作用户id
        String jwt = request.getHeader("token");
        Map<String, Object> claims = JwtUtils.parseJwt(jwt);
        Integer operateUser = (Integer) claims.get("id");
        //获取操作时间
        LocalDateTime operateTime = LocalDateTime.now();
        //获取操作的类名
        String operateClass = joinPoint.getTarget().getClass().getName();
        //获取操作的方法名
        String operateMethod = joinPoint.getSignature().getName();
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        String methodParams = Arrays.toString(args);
        //获取返回值(JSON字符串格式)
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        String returnValue = JSONObject.toJSONString(result);
        //获取方法执行耗时
        Long costTime = endTime - startTime;
        OperateLog operateLog = new OperateLog(null,operateUser,operateTime,operateClass,
                operateMethod,methodParams,returnValue,costTime);
        operateLodMapper.insert(operateLog);
        log.info("AOP记录操作日志:{}",operateLog);
        return result;
    }

}
在Controller中添加注解:
EmpController:
@Slf4j
@RequestMapping("/emps")
@RestController
public class EmpController {

    @Autowired
    private EmpService empService;

    /**
     * 根据每页记录数和页码获取页面实体类
     * @return
     */
    @GetMapping
    public Result getPage(@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("每页记录数:{},查询页码:{}",pageSize,page);
        PageBean pb = empService.getPage(page,pageSize,name,gender,begin,end);
        return Result.success(pb);
    }

    /**
     * 批量删除员工
     * @param ids
     * @return
     */
    @Log
    @DeleteMapping("/{ids}")
    public Result delete(@PathVariable("ids") List<Short> ids) {
        log.info("批量删除操作ids:{}",ids);
        empService.delete(ids);
        return Result.success();
    }

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

    /**
     * 根据id查询员工
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("查询id为:{}的员工",id);
        Emp emp = empService.getById(id);
        return Result.success(emp);
    }

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

}
DeptController:
@Slf4j
@RequestMapping("/depts")
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

    /**
     * 查询部门数据
     * @return
     */
    @GetMapping
    public Result list() {
        log.info("查询全部部门信息");
        List<Dept> deptList = deptService.list();
        return Result.success(deptList);
    }

    /**
     * 删除部门
     * @return
     */
    @Log
    @DeleteMapping("/{id}")
    public Result delete(@PathVariable Integer id) {
        log.info("删除id为" + id +"的部门");
        deptService.delete(id);
        return Result.success();
    }

    /**
     * 新增部门
     * @param dept
     * @return
     */
    @Log
    @PostMapping
    public Result insert(@RequestBody Dept dept) {
        log.info("添加部门:" + dept);
        deptService.add(dept);
        return Result.success();
    }

    /**
     * 根据id查找部门
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id) {
        log.info("查询id为"+ id + "的部门信息");
        Dept dept = deptService.get(id);
        return Result.success(dept);
    }

    /**
     * 修改部门
     * @param dept
     * @return
     */
    @Log
    @PutMapping
    public Result update(@RequestBody Dept dept) {
        log.info("修改部门:" + dept);
        deptService.update(dept);
        return Result.success();
    }

}
注意点:

        在获取操作用户id时要用到以下方法:

SpringBoot

配置优先级:

1.properties>yml>yaml

2.命令行参数>Java系统属性

项目打包之后在cmd运行时设置属性或参数

3.命令行参数>Java系统属性

        并且在SpringBoot中直接配置Java系统属性后,再使用配置文件配置,那么会根据Java系统属性的配置信息配置

总结:

        优先级:命令行参数>Java系统属性>properties>yml>yaml

 打包方式:

bean的管理:

获取bean:

代码演示:
    /**
     * 获得bean对象
     */
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void testGetBean(){
        //通过name获取bean
        DeptController bean1 = (DeptController) applicationContext.getBean("deptController");
        System.out.println(bean1);

        //通过类型获取bean
        DeptController bean2 = applicationContext.getBean(DeptController.class);
        System.out.println(bean2);

        //通过name获取bean(带类型转换)
        DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);
        System.out.println(bean3);

    }


}
运行结果:

bean的作用域:

第三方bean:

        (以xml解析类SAXReader举例)

使用场景:

★SpringBoot原理:

起步依赖:

        如果要使用web相关的依赖,只需要导入spring-boot-starter-web依赖,通过maven的依赖传递,关于web的所有依赖都会被导入,还不用担心版本兼容问题

自动配置:

自动配置的原理:
问题:

        如果我们直接在pom.xml.文件中引入第三方依赖,第三方依赖中通过@Component、@Bean等注解定义了bean对象,这种情况第三方依赖中的bean对象也是不会出现在springboot程序中的,因为springboot程序通过启动类注解@SpringBootApplication扫描其所在包和子包中的bean对象,是扫描不到第三方依赖的。

解决方案一 @ComponentScan组件扫描:

启动类:(com.han为当前启动类所在包,com.example为第三方依赖的包)

@ComponentScan({"com.han","com.example"})
@ServletComponentScan
@SpringBootApplication
public class TliasApplication {

	public static void main(String[] args) {
		SpringApplication.run(TliasApplication.class, args);
	}

}

        这种方式使用较繁琐,性能低。

解决方案二 @Import导入:

@EnableXxxx注解使用举例:

@SpringBootApplication源码跟踪:

        这里最重要的是@EnableAutoConfiguration注解。

@EnableAutoConfiguration:

        它通过封装@Import注解,将上图两个文件中的需要导入到IOC容器的类的全类名放入ImportSelector接口的实现类中的selectImports方法返回的字符数组,以自动配置。

        但是这些类并不是全部注册为IOC容器的bean,SpringBoot会根据@Conditional注解条件装配

条件装配注解@Conditional:

1.@ConditionalOnClass:

2.@ConditionalOnMissingBean:

        不指定类型和名称时,默认类型指该方法返回值的类型。

        使用场景:默认的bean,引入依赖后,用户如果自定义了这个类型的bean,则会导入用户自定义的,如果用户没有定义,就导入依赖中默认的。

3.@ConditionalOnProperty:

        根据上述代码,若在配置文件application.yml中添加配置信息name: itheima,那么就会将该bean放入IOC容器中。

        使用场景:引入第三方变量后,可以在配置文件中配置信息后,才将某个类加入IOC容器。

案例(自定义starter):

自定义starter场景:

案例需求:

步骤:

代码:

1.新建模块aliyun-oss-spring-boot-starter(只需要pom.xml文件),aliyun-oss-spring-boot-autoconfigure(只需要pom.xml文件和src文件夹,也不需要启动类),在aliyun-oss-spring-boot-starter中的pom.xml文件中引入aliyun-oss-spring-boot-autoconfigure的依赖。

 aliyun-oss-spring-boot-starter:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-oss-spring-boot-starter</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<java.version>17</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>com.aliyun.oss</groupId>
			<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>

	</dependencies>


</project>

2.在aliyun-oss-spring-boot-autoconfigure中的pom.xml文件中引入阿里云OSS的依赖

aliyun-oss-spring-boot-autoconfigure:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<java.version>17</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<!--阿里云OSS依赖-->
		<dependency>
			<groupId>com.aliyun.oss</groupId>
			<artifactId>aliyun-sdk-oss</artifactId>
			<version>3.15.1</version>
		</dependency>
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.3.1</version>
		</dependency>
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
			<version>1.1.1</version>
		</dependency>


	</dependencies>


</project>

3.在aliyun-oss-spring-boot-autoconfigure中编写能够使用阿里云OSS的代码

这里要使用MultipartFile还需要引入web开发的起步依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.2.6</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.aliyun.oss</groupId>
	<artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<java.version>17</java.version>
	</properties>

	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<!--阿里云OSS依赖-->
		<dependency>
			<groupId>com.aliyun.oss</groupId>
			<artifactId>aliyun-sdk-oss</artifactId>
			<version>3.15.1</version>
		</dependency>
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.3.1</version>
		</dependency>
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
			<version>1.1.1</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

	</dependencies>


</project>

工具类:

/**
 * 阿里云 OSS 工具类
 */
public class AliOSSUtils {
    

    private AliOSSProperties aliOSSProperties;

    //不能依赖注入了但是后续方法要使用aliOSSProperties对象,所以定义get set方法
    public AliOSSProperties getAliOSSProperties() {
        return aliOSSProperties;
    }

    public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {
        this.aliOSSProperties = aliOSSProperties;
    }

    /**
     * 实现上传图片到OSS
     */
    public String upload(MultipartFile file) throws ClientException, IOException {

        String endpoint = aliOSSProperties.getEndpoint();
        String bucketName = aliOSSProperties.getBucketName();

        InputStream inputStream = file.getInputStream();

        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Object完整路径,例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
        String objectName = file.getOriginalFilename();

        String fileName = UUID.randomUUID().toString() + objectName.substring(objectName.lastIndexOf("."));
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件。

        // 创建OSSClient实例
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);


        // 创建PutObjectRequest对象。
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, fileName, inputStream);
        // 上传文件。
        PutObjectResult result = ossClient.putObject(putObjectRequest);


        // 设置请求头。
        Map<String, String> headers = new HashMap<String, String>();
        /*// 指定Object的存储类型。
        headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
        // 指定ContentType。
        headers.put(OSSHeaders.CONTENT_TYPE, "text/txt");*/

        // 设置用户自定义元数据。
        Map<String, String> userMetadata = new HashMap<String, String>();
        /*userMetadata.put("key1","value1");
        userMetadata.put("key2","value2");*/

        URL signedUrl = null;
        // 指定生成的签名URL过期时间,单位为毫秒。本示例以设置过期时间为1小时为例。
        Date expiration = new Date(new Date().getTime() + 3600 * 1000L);

        // 生成签名URL。
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, fileName);
        // 设置过期时间。
        request.setExpiration(expiration);

        // 将请求头加入到request中。
        request.setHeaders(headers);
        // 添加用户自定义元数据。
        request.setUserMetadata(userMetadata);

        // 通过HTTP PUT请求生成签名URL。
        signedUrl = ossClient.generatePresignedUrl(request);
        // 返回签名URL。
        ossClient.shutdown();
        return signedUrl.toString().split("\\?")[0];
    }

}

认证信息存储类:

@ConfigurationProperties(prefix = "aliyun.oss")//用于验证配置文件中以"aliyun.oss"为前缀的属性
public class AliOSSProperties {
    private String endpoint;
    private String bucketName;

    public String getEndpoint() {
        return endpoint;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }

}

4.定义自动配置类AliOSSAutoConfiguration

@Configuration//配置类
@EnableConfigurationProperties(AliOSSProperties.class)//将AliOSSProperties类bean对象放入IOC容器
public class AliOSSAutoConfiguration {

    @Bean
     public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties){//需要注入某个对象直接在方法形参中指定
        AliOSSUtils aliOSSUtils = new AliOSSUtils();
        aliOSSUtils.setAliOSSProperties(aliOSSProperties);
         return aliOSSUtils;
     }

}

5.定义自动配置文件,在resource目录下创建文件夹META-INF/spring下的文件org.springframework.boot.autoconfigure.AutoConfiguration

并存入配置类的全类名

com.aliyun.oss.AliOSSAutoConfiguration

测试案例:

        新建模块,配置阿里云OSS信息

application.yml:

#阿里云OSS配置
aliyun:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    bucketName: web-talias-test

        引入自定义的依赖,只需要引入starter

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.han</groupId>
    <artifactId>springboot-autoconfiguration-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-autoconfiguration-test</name>
    <description>springboot-autoconfiguration-test</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-oss-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

编写Controller:

@RestController
public class UploadController {

    @Autowired
    private AliOSSUtils aliOSSUtils;

    @PostMapping("/upload")
    public String upload(MultipartFile image) throws Exception {

        String url = aliOSSUtils.upload(image);

        return url;

    }


}

Postman测试:

        浏览器打开网址可正常下载显示。

框架总结:

                                                SpringMVC + Spring framework(Spring) + Mybatis = SSM框架

        SpringMVC属于Spring框架,是Spring框架当中提供的web开发模块,是用来简化原始的servelet程序的开发的。

        基于传统的SSM框架开发进行整合开发是比较繁琐的,效率也较低,所以目前的企业项目开发当中,基本上都是基于SpringBoot进行项目开发的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1795863.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新能源管理系统主要包括哪些方面的功能?

随着全球对可持续发展和环境保护的日益重视&#xff0c;新能源管理系统已成为现代能源领域的核心组成部分。这一系统不仅涉及对新能源的收集、存储和管理&#xff0c;还包括对整个能源网络进行高效、智能的监控和控制。以下是新能源管理系统主要包含的几方面功能&#xff1a; 一…

ESP32 Error creating RestrictedPinnedToCore

随缘记&#xff0c;刚遇到&#xff0c;等以后就可能不想来写笔记了。 目前要使用到音频数据&#xff0c;所以去用ESP-ADF&#xff0c;但在使用例程上出现了这个API有问题&#xff0c;要去打补丁。 但是我打补丁的时候git bash里显示not apply&#xff0c;不能打上。 网上看到…

谷歌账号的注册到使用GitHub

一、浏览器扩展 浏览器扩展谷歌学术 二、注册谷歌邮箱 https://support.google.com/accounts/answer/27441?hlzh-hans 1.打开无痕模式&#xff08;ctrlshiftn&#xff09; 2.输入网址 3.选择个人账号 4.填写信息&#xff08;随便填就行&#xff09; &#xff08;以上步骤有时…

FTP

文章目录 概述主动模式和被动模式的工作过程注意事项 概述 文件传输协议 FTP&#xff08;File Transfer Protocol&#xff09;在 TCP/IP 协议族中属于应用层协议&#xff0c;是文件传输标准。主要功能是向用户提供本地和远程主机之间的文件传输&#xff0c;尤其在进行版本升级…

【YOLOV8】2.目标检测-训练自己的数据集

Yolo8出来一段时间了,包含了目标检测、实例分割、人体姿态预测、旋转目标检测、图像分类等功能,所以想花点时间总结记录一下这几个功能的使用方法和自定义数据集需要注意的一些问题,本篇是第二篇,目标检测功能,自定义数据集的训练。 YOLO(You Only Look Once)是一种流行的…

基于element ui 城市选择之间的级联选择

通过el-select实现城市的级联选择效果如图所示 代码实现 <template><div><el-form :model"ruleForminfo"><el-form-item label"居住地址" required><el-col :span"6"><el-form-item ><el-select v-mode…

tsconfig.json和tsconfig.app.json文件解析(vue3+ts+vite)

tsconfig.json {"files": [],"references": [{"path": "./tsconfig.node.json"},{"path": "./tsconfig.app.json"}] }https://www.typescriptlang.org/tsconfig/#files files: 在这个例子中&#xff0c;files 数…

表格中附件的上传、显示以及文件下载#Vue3#后端接口数据

表格中附件的上传及显示#Vue3#后端接口数据 一、图片上传并显示在表格中实现效果&#xff1a; 表格中上传附件 代码&#xff1a; <!-- 文件的上传及显示 --> <template><!-- 演示地址 --><div class"dem-add"><!-- Search start -->…

手写节流throttle

节流throttle 应用场景 滚动事件监听scroll&#xff1a;例如监听页面滚动到底部加载更多数据时&#xff0c;使用节流技术减少检查滚动位置的频率&#xff0c;提高性能。鼠标移动事件mousemove&#xff1a;例如实现一个拖拽功能&#xff0c;使用节流技术减少鼠标移动事件的处理…

PHPStudy(xp 小皮)V8.1.1 通过cmd进入MySQL命令行模式

PHPStudy是一个PHP开发环境集成包&#xff0c;可用在本地电脑或者服务器上&#xff0c;该程序包集成最新的PHP/MySql/Apache/Nginx/Redis/FTP/Composer&#xff0c;一次性安装&#xff0c;无须配置即可使用。MySQL MySQL是一个关系型数据库管理系统&#xff0c;由瑞典 MySQL A…

MongoDB环境搭建

一.下载安装包 Download MongoDB Community Server | MongoDB 二、双击下载完成后的安装包开始安装&#xff0c;除了以下两个部分需要注意操作&#xff0c;其他直接next就行 三.可视化界面安装 下载MongoDB-compass&#xff0c;地址如下 MongoDB Compass Download (GUI) | M…

使用LeanCloud平台的即时通讯

LeanCloud 是领先的 Serverless 云服务&#xff0c;为产品开发提供强有力的后端支持&#xff0c;旨在帮助开发者降低研发、运营维护等阶段投入的精力和成本。 LeanCloud 整合了各项服务&#xff0c;让开发者能够聚焦在核心业务上&#xff0c;为客户创造更多价值。 *即时通讯 …

15、matlab绘图汇总(图例、标题、坐标轴、线条格式、颜色和散点格式设置)

1、plot()函数默认格式画图 代码&#xff1a; x0:0.1:20;%绘图默认格式 ysin(x); plot(x,y) 2、X轴和Y轴显示范围/axis()函数 代码&#xff1a; x0:0.1:20;%绘图默认格式 ysin(x); plot(x,y) axis([0 21 -1.1 1.1])%设置范围 3、网格显示/grid on函数 代码&#xff1a; …

设备上CCD功能增加(从接线到程序)

今天终于完成了一个上面交给我的一个小项目&#xff0c;给设备增加一个CCD拍照功能&#xff0c;首先先说明一下本次使用基恩士的CCD相机&#xff0c;控制器&#xff0c;还有软件&#xff08;三菱程序与基恩士程序&#xff09;。如果对你有帮助&#xff0c;欢迎评论收藏&#xf…

VMware Workstation中WinXP联网问题

我一直以为我的虚拟机上的XP没有联网 因为 蒙了半天&#xff0c;发现是因为这个网址打不开&#xff0c;不是没有网 太傻了 不如在cmd命令行中通过ping baidu.com来判断是否联网

Dubbo 自定义 Filter 编码实例

Dubbo的Filter机制为我们做应用的扩展设计提供了很多可能性&#xff0c;这里的Filter也是“责任链”机制的一种实现场景&#xff0c;作为Java码农&#xff0c;我们也经常接触到很多责任链的实现场景&#xff0c;如Tomcat进入Servlet前的filter&#xff0c;如Spring Aop代理的链…

语言模型解构——Tokenizer

1. 认识Tokenizer 1.1 为什么要有tokenizer&#xff1f; 计算机是无法理解人类语言的&#xff0c;它只会进行0和1的二进制计算。但是呢&#xff0c;大语言模型就是通过二进制计算&#xff0c;让你感觉计算机理解了人类语言。 举个例子&#xff1a;单1&#xff0c;双2&#x…

龙迅LT8712X TYPE-C或者DP转HDMI加VGA输出,内置MCU,只是IIS以及4K60HZ分辨率

龙迅LT8712X描述&#xff1a; LT8712X是一种高性能的Type-C/DP1.2到HDMI2.0和VGA转换器&#xff0c;设计用于将USB Type-C源或DP1.2源连接到HDMI2.0和VGA接收器。LT8712X集成了一个DP1.2兼容的接收器&#xff0c;一个HDMI2.0兼容的发射机和一个高速三角机窝视频DAC。此外&…

【论文速读】LM的文本生成方法,Top-p,温度,《The Curious Case of Neural Text Degeneration》

论文链接&#xff1a;https://arxiv.org/abs/1904.09751 https://ar5iv.labs.arxiv.org/html/1904.09751 这篇文章&#xff0c;描述的是语言模型的文本生成的核采样的方法&#xff0c;就是现在熟知的top-p 大概看看&#xff0c;还有几个地方比较有趣&#xff0c;值得记录一下。…

kotlin1.8.10问题导致gson报错TypeToken type argument must not contain a type variable

书接上回&#xff0c;https://blog.csdn.net/jzlhll123/article/details/139302991。 之前我发现gson报错后&#xff1a; gson在2.11.0给我的kotlin项目代码报错了。 IllegalArgumentException: TypeToken type argument must not contain a type variable 上次解释原因是因为&…