文章目录
- 表数据加密
- 文档与日志接入
- swagger常用注解
- 管理端 员工管理模块开发
- 员工信息新增实现
- 新增员工代码完善
- ThreadLocal
- 员工分页查询
- 账户启用 禁用切换
- 编辑员工
- 1 回显员工信息功能
- 2 修改员工信息功能
- 导入分类模块功能代码
项目地址 https://gitee.com/lyh1999/minjiang-takeout
表数据加密
员工表中密码明文存储 需要加密 将密码加密后存储到数据库 使用MD5加密 (MD5信息摘要算法 )加密后生成一个32位的字符串
MD5 可以被破解 推荐使用SHA-2算法
完善登录
1 修改数据库中明文密码 改为MD5加密后的密文
2 修改JAVA代码 前端提交密码 进行MD5加密后与数据库中的密码密文对比
spring 提供的MD5加密
password = DigestUtils.md5DigestAsHex(password.getBytes())
if(!password.equals(employee.getPassword(){
//密码错误
throw new PasswordErrorException(MessageConstant.PASSWORD_ERROE)
}))
TODO 注释
spring进行的md5加密属于小写字母的md5加密
文档与日志接入
Swagger
生成接口文档和进行接口测试
swagger官网 https://swagger.io/
knife4j是 java MVC 框架集成swagger生成api文档的增强解决方案
在pom.xml导入
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
knife4j使用方式
1 导入knife4j的maven坐标
2 在配置类中加入knife4j相关配置
3 设置静态资源映射
在配置类中(sky-server>com.sky/config/WebMvcConfiguration)
@Bean
public Docket docket() {
ApiInfo apiInfo = new ApiInfoBuilder()
.title("闽江外卖项目接口文档")
.version("2.0")
.description("闽江外卖项目接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.sky.controller")) // 指向扫描的包
.paths(PathSelectors.any())
.build();
return docket;
}
/**
* 设置静态资源映射
* @param registry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
启动项目后 访问 http://localhost:8080/doc.html
即可得到swagger在线文档
swagger常用注解
@Api 用在类上 对类做说明 如controller
@ApiModel 用在类上 entity DTO VO
@ApiModelProperty 用在属性上
@ApiOperation 用在方法上 如Controller的方法
@Api(tags = "员工相关接口")
public class EmployeeController {}
@PostMapping("/login")
@ApiOperation(value = "员工登录")
@ApiOperation(value = "员工退出")
@PostMapping("/logout")
@ApiModel(description = "员工登录时传递的数据模型")
public class EmployeeLoginDTO implements Serializable {
@ApiModelProperty("用户名")
private String username;
@ApiModelProperty("密码")
private String password;
}
@ApiModel(description = "员工登录返回的数据格式")
public class EmployeeLoginVO implements Serializable {
@ApiModelProperty("主键值")
private Long id;
@ApiModelProperty("用户名")
private String userName;
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("jwt令牌")
private String token;
}
添加注解 能让knife4j生成的swagger文档更加清晰易懂
管理端 员工管理模块开发
新增员工 分页查询 启用禁用员工账户 员工信息编辑
新增员工 需求分析和设计 代码开发 功能测试 代码完善
员工信息新增实现
填写员工信息时后端校验
账号唯一性
手机号合法11位数据
身份证号合法18位数据
本项目约定 管理端请求 统一使用/admin做前缀
用户端 统一采用/user做前缀
前端提交数据和实体类对应属性差别较大时 封装DTO对象
@Data
public class EmployeeDTO implements Serializable {
private Long id;
private String username;
private String name;
private String phone;
private String sex;
private String idNumber;
}
save实现
/**
*
* @param employeeDTO
* @return
*/
@PostMapping
@ApiOperation(value = "新增员工")
public Result save(@RequestBody EmployeeDTO employeeDTO){
log.info("新增员工:{}",employeeDTO);
employeeService.save(employeeDTO);
return Result.success();
}
public interface EmployeeService {
/**
* 员工登录
* @param employeeLoginDTO
* @return
*/
Employee login(EmployeeLoginDTO employeeLoginDTO);
/**
*
* @param 新增员工
*/
void save(EmployeeDTO employeeDTO);
}
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
public void save(EmployeeDTO employeeDTO) {
//调用持久层mapper 插入数据
Employee employee = new Employee();
//employee.setName(employeeDTO.getName());
//对象属性拷贝
BeanUtils.copyProperties(employeeDTO, employee);
// 设置账户状态 1 表示正常 0表示锁定
employee.setStatus(StatusConstant.ENABLE);
// 设置账户密码 默认123456
employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
// 设置当前记录创建时间和修改时间
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
// 设置当前记录人创建id和修改id
// 暂时写死
// TODO 后期需要改为当前用户id值
employee.setCreateUser(10L);
employee.setUpdateUser(10L);
employeeMapper.insert(employee);
}
}
/**
* 插入员工数据
* @param employee
*/
@Insert("insert into employee(name,username,password,phone,sex,id_number,status,create_time,update_time,create_user,update_user)" +
"values " +
"(#{name},#{username},#{password},#{phone},#{sex},#{idNumber},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})"
)
@AutoFill(value = OperationType.INSERT)
void insert(Employee employee);
EmployeeController =》 EmployeeService =》 EmployeeServiceImpl =》 employeeMapper
新增员工代码完善
1 录入用户名已存在 抛出异常后未处理
2 新增员工 创建id 和修改id设置的固定值
通过全局异常处理器来处理。
进入到sky-server模块,com.sky.hander包下,GlobalExceptionHandler.java添加方法
@ExceptionHandler
public Result exceptionHandler(SQLIntegrityConstraintViolationException ex){
String message = ex.getMessage();
if(message.contains("Duplicate entry")){
// 返回的错误信息包含Duplicate entry 重复的条目
String[] split = message.split(" ");
String username = split[2] + MessageConstant.AlREADY_EXISTS;
String msg = username + "已存在";
return Result.error(msg);
}else{
// 其他异常
return Result.error(MessageConstant.UNKNOWN_ERROR);
}
}
调试时 报401可能是token已过期 重启项目 token会更换
jwt流程
前端 用户认证 提交 用户名 和密码 后端认证通过 生成jwt token 前端 保存jwt token在本地
前端 每次请求 后端接口 在请求头中携带jwt token 后端 拦截请求验证 jwt token 通过 执行业务逻辑 返回数据 前端展示数据
后端不通过 返回错误信息 前端展示错误信息 并返回登录页面
新增员工时,创建人id和修改人id设置为固定值
package com.sky.controller.admin;
/**
* 员工管理
*/
@RestController
@RequestMapping("/admin/employee")
@Slf4j
@Api(tags = "员工相关接口")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@Autowired
private JwtProperties jwtProperties;
/**
* 登录
*
* @param employeeLoginDTO
* @return
*/
@PostMapping("/login")
@ApiOperation(value = "员工登录")
public Result<EmployeeLoginVO> login(@RequestBody EmployeeLoginDTO employeeLoginDTO) {
//.........
//登录成功后,生成jwt令牌
Map<String, Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.EMP_ID, employee.getId());
String token = JwtUtil.createJWT(
jwtProperties.getAdminSecretKey(),
jwtProperties.getAdminTtl(),
claims);
//............
return Result.success(employeeLoginVO);
}
}
后续请求中,前端会携带JWT令牌,通过JWT令牌可以解析出当前登录员工id:
JwtTokenAdminInterceptor.java
package com.sky.interceptor;
/**
* jwt令牌校验的拦截器
*/
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 校验jwt
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//..............
//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//2、校验令牌
try {
log.info("jwt校验:{}", token);
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
log.info("当前员工id:", empId);
//3、通过,放行
return true;
} catch (Exception ex) {
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
}
前端携带jwt令牌 通过jwt令牌 解析当前登录用户员工id
解析出登录员工id后,如何传递给Service的save方法?
通过ThreadLocal进行传递。
ThreadLocal
ThreadLocal 是 Java 提供的一种机制,它为每个线程创建独立的变量副本,使得同一个类的实例在不同线程中拥有不同的状态。这种方式非常适合用来存储与当前线程相关的数据,例如用户会话信息、事务上下文等。
在基于JWT的身份验证场景中,使用 ThreadLocal 的方式可以确保在请求处理的过程中,从解析出的JWT中提取到的员工ID(或其他用户相关信息)可以在整个请求链中被访问到,而无需通过参数传递。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
ThreadLocal 常用方法:
- public void set(T value) 设置当前线程的线程局部变量的值
- public T get() 返回当前线程所对应的线程局部变量的值
- public void remove() 移除当前线程的线程局部变量
初始工程中已经封装了 ThreadLocal 操作的工具类:
在sky-common模块
package com.sky.context;
public class BaseContext {
public static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
public static void setCurrentId(Long id) {
threadLocal.set(id);
}
public static Long getCurrentId() {
return threadLocal.get();
}
public static void removeCurrentId() {
threadLocal.remove();
}
}
在拦截器中解析出当前登录员工id,并放入线程局部变量中:
在sky-server模块中,拦截器:
@Component
@Slf4j
public class JwtTokenAdminInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
/**
* 校验jwt
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("当前线程id值为"+ Thread.currentThread().getId());
//判断当前拦截到的是Controller的方法还是其他资源
if (!(handler instanceof HandlerMethod)) {
//当前拦截到的不是动态方法,直接放行
return true;
}
//1、从请求头中获取令牌
String token = request.getHeader(jwtProperties.getAdminTokenName());
//2、校验令牌
try {
log.info("jwt校验:{}", token);
Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);
Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());
log.info("当前员工id:", empId);
// 存入员工id到ThreadLocal
BaseContext.setCurrentId(empId);
//3、通过,放行
return true;
} catch (Exception ex) {
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
}
在Service中获取线程局部变量中的值:
public void save(@RequestBody EmployeeDTO employeeDTO) {
//调用持久层mapper 插入数据
Employee employee = new Employee();
//employee.setName(employeeDTO.getName());
//对象属性拷贝
BeanUtils.copyProperties(employeeDTO, employee);
// 设置账户状态 1 表示正常 0表示锁定
employee.setStatus(StatusConstant.ENABLE);
// 设置账户密码 默认123456
employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
// 设置当前记录创建时间和修改时间
// employee.setCreateTime(LocalDateTime.now());
// employee.setUpdateTime(LocalDateTime.now());
// 设置当前记录人创建id和修改id
// 暂时写死
// TODO 后期需要改为当前用户id值
System.out.println("当前线程id值为"+ Thread.currentThread().getId());
employee.setCreateUser(BaseContext.getCurrentId());
employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.insert(employee);
}
测试:使用admin(id=1)用户登录后添加一条记录 新增用户
员工分页查询
- 根据页码展示员工信息
- 每页展示10条数据
- 分页查询时可以根据需要,输入员工姓名进行查询
封装DTO
@Data
public class EmployeePageQueryDTO implements Serializable {
//员工姓名
private String name;
//页码
private int page;
//每页显示记录数
private int pageSize;
}
分页查询结果 不采用result对象 封装为 pageResult对象
/**
* 封装分页查询结果
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {
private long total; //总记录数
private List records; //当前页数据集合
}
员工信息分页查询后端返回的对象类型为: Result
@Data
public class Result<T> implements Serializable {
private Integer code; //编码:1成功,0和其它数字为失败
private String msg; //错误信息
private T data; //数据
public static <T> Result<T> success() {
Result<T> result = new Result<T>();
result.code = 1;
return result;
}
public static <T> Result<T> success(T object) {
Result<T> result = new Result<T>();
result.data = object;
result.code = 1;
return result;
}
public static <T> Result<T> error(String msg) {
Result result = new Result();
result.msg = msg;
result.code = 0;
return result;
}
}
Controller层
/**
* 实现分页查询
* @param
*/
@GetMapping("/page")
@ApiOperation(value = "员工分页查询")
public Result<PageResult> page(EmployeePageQueryDTO employeePageQueryDTO){
log.info("员工分页查询:{}",employeePageQueryDTO);
PageResult pageResult = employeeService.pageQuery(employeePageQueryDTO);
return Result.success(pageResult);
}
Service层接口
在EmployeeService接口中声明pageQuery方法:
/**
* 分页查询方法
* @param employeePageQueryDTO
* @return
*/
PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
Service层实现类
@Override
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
// 底层基于数据库分页
// select * from employee limit 0,10
// 这里采用mybatis的插件 pageHelper
PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
// 返回page对象
Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
// 获取总记录数
long total = page.getTotal();
// 获取当前页的数据
List<Employee> records = page.getResult();
return new PageResult(total, records);
}
在pom.xml文中添加依赖(初始工程已添加)
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper}</version>
</dependency>
Mapper层
/**
* 分页查询方法
* 动态sql 注解不适合 采用映射文件书写sql resources/mapper/employeeMapper.xml
* @param employeePageQueryDTO
* @return
*/
Page<Employee> pageQuery(EmployeePageQueryDTO employeePageQueryDTO);
<select id="pageQuery" resultType="com.sky.entity.Employee">
select * from employee
<where>
<if test="name!=null and name!=''">
and name like concat('%',#{name},'%')
</if>
</where>
order by create_time desc
</select>
测试查询分页列表数据
代码完善 时间格式化 两种方式
1 在属性上加上注解,对日期进行格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
但这种方式,需要在每个时间属性上都要加上该注解,使用较麻烦,不能全局处理。
2 在WebMvcConfiguration中扩展SpringMVC的消息转换器,统一对日期类型进行格式处理
/**
* 扩展Spring MVC框架的消息转化器
* @param converters
*/
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
log.info("扩展消息转换器...");
//创建一个消息转换器对象
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
//需要为消息转换器设置一个对象转换器,对象转换器可以将Java对象序列化为json数据
converter.setObjectMapper(new JacksonObjectMapper());
//将自己的消息转化器加入容器中
converters.add(0,converter);
}
在 JacksonObjectMapper 定义固定的时间对象
public class JacksonObjectMapper extends ObjectMapper {
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
//public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
public JacksonObjectMapper() {
super();
//收到未知属性时不报异常
this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);
//反序列化时,属性不存在的兼容处理
this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule simpleModule = new SimpleModule()
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
//注册功能模块 例如,可以添加自定义序列化器和反序列化器
this.registerModule(simpleModule);
}
}
账户启用 禁用切换
账户禁用时不能登录
传递status值 做路径参数 和员工id 做查询参数
@PostMapping("/status/{status}")
@ApiOperation(value = "启用禁用员工账户")
public Result startOrStop(@PathVariable("status") Integer status, Long id){
log.info("启用禁用员工账户:{},{}",status,id);
employeeService.startOrStop(status,id);
return Result.success();
}
/**
* 启用或禁用员工账户
* @param status
* @param id
*/
void startOrStop(Integer status, Long id);
@Override
public void startOrStop(Integer status, Long id) {
// update employee set status = #{status} where id = #{id}
// 更新可能适配多种状态 直接传两个写死参数不适合 传递一个对象 第一种写法
// Employee employee = new Employee();
// employee.setStatus(status);
// employee.setId(id);
// 第二种写法 因为 employee对象添加了@builder注解 建造者模式实现
Employee employee = Employee.builder().status(status).id(id).build();
employeeMapper.update(employee);
}
<update id="update" parameterType="Employee">
update employee
<set>
<if test="name!=null">
name=#{name},
</if>
<if test="username!=null">
username=#{username},
</if>
<if test="password!=null">
password=#{password},
</if>
<if test="phone!=null">
phone=#{phone},
</if>
<if test="sex!=null">
sex=#{sex},
</if>
<if test="idNumber!=null">
id_Number=#{idNumber},
</if>
<if test="updateTime!=null">
update_Time=#{updateTime},
</if>
<if test="updateUser!=null">
update_User=#{updateUser},
</if>
<if test="status!=null">
status=#{status}
</if>
</set>
where id=#{id}
</update>
xml 的更新属性 只判空
编辑员工
根据id 查询员工信息 并回显
编辑员工信息
1 回显员工信息功能
Controller层
在 EmployeeController 中创建 getById 方法:
/**
* 根据id查询员工信息
* @param id
* @return
*/
@GetMapping("/{id}")
@ApiOperation("根据id查询员工信息")
public Result<Employee> getById(@PathVariable Long id){
Employee employee = employeeService.getById(id);
return Result.success(employee);
}
Service层接口
在 EmployeeService 接口中声明 getById 方法:
/**
* 根据id查询员工
* @param id
* @return
*/
Employee getById(Long id);
Service层实现类
在 EmployeeServiceImpl 中实现 getById 方法:
/**
* 根据id查询员工
*
* @param id
* @return
*/
public Employee getById(Long id) {
Employee employee = employeeMapper.getById(id);
employee.setPassword("****");
return employee;
}
Mapper层
在 EmployeeMapper 接口中声明 getById 方法:
/**
* 根据id查询员工信息
* @param id
* @return
*/
@Select("select * from employee where id = #{id}")
Employee getById(Long id);
2 修改员工信息功能
Controller层
在 EmployeeController 中创建 update 方法:
/**
* 编辑员工信息
* @param employeeDTO
* @return
*/
@PutMapping
@ApiOperation("编辑员工信息")
public Result update(@RequestBody EmployeeDTO employeeDTO){
log.info("编辑员工信息:{}", employeeDTO);
employeeService.update(employeeDTO);
return Result.success();
}
Service层接口
在 EmployeeService 接口中声明 update 方法:
/**
* 编辑员工信息
* @param employeeDTO
*/
void update(EmployeeDTO employeeDTO);
Service层实现类
在 EmployeeServiceImpl 中实现 update 方法:
/**
* 编辑员工信息
* @param employeeDTO
*/
public void update(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
// 使用BeanUtils的copyProperties方法将employeeDTO的属性复制到employee对象中
BeanUtils.copyProperties(employeeDTO, employee);
// 设置更新时间
employee.setUpdateTime(LocalDateTime.now());
// 设置更新人
employee.setUpdateUser(BaseContext.getCurrentId());
// 调用mapper持久层的update方法
employeeMapper.update(employee);
}
导入分类模块功能代码
实现菜品分类和套餐分类
- 新增分类
- 分类分页查询
- 根据id删除分类
- 修改分类
- 启用禁用分类
- 根据类型查询分类
controller层
/**
* 分类管理
*/
@RestController
@RequestMapping("/admin/category")
@Api(tags = "分类相关接口")
@Slf4j
public class CategoryController {
@Autowired
private CategoryService categoryService;
/**
* 新增分类
* @param categoryDTO
* @return
*/
@PostMapping
@ApiOperation("新增分类")
public Result<String> save(@RequestBody CategoryDTO categoryDTO){
log.info("新增分类:{}", categoryDTO);
categoryService.save(categoryDTO);
return Result.success();
}
/**
* 分类分页查询
* @param categoryPageQueryDTO
* @return
*/
@GetMapping("/page")
@ApiOperation("分类分页查询")
public Result<PageResult> page(CategoryPageQueryDTO categoryPageQueryDTO){
log.info("分页查询:{}", categoryPageQueryDTO);
PageResult pageResult = categoryService.pageQuery(categoryPageQueryDTO);
return Result.success(pageResult);
}
/**
* 删除分类
* @param id
* @return
*/
@DeleteMapping
@ApiOperation("删除分类")
public Result<String> deleteById(Long id){
log.info("删除分类:{}", id);
categoryService.deleteById(id);
return Result.success();
}
/**
* 修改分类
* @param categoryDTO
* @return
*/
@PutMapping
@ApiOperation("修改分类")
public Result<String> update(@RequestBody CategoryDTO categoryDTO){
categoryService.update(categoryDTO);
return Result.success();
}
/**
* 启用、禁用分类
* @param status
* @param id
* @return
*/
@PostMapping("/status/{status}")
@ApiOperation("启用禁用分类")
public Result<String> startOrStop(@PathVariable("status") Integer status, Long id){
categoryService.startOrStop(status,id);
return Result.success();
}
/**
* 根据类型查询分类
* @param type
* @return
*/
@GetMapping("/list")
@ApiOperation("根据类型查询分类")
public Result<List<Category>> list(Integer type){
List<Category> list = categoryService.list(type);
return Result.success(list);
}
}
service层
public interface CategoryService {
/**
* 新增分类
* @param categoryDTO
*/
void save(CategoryDTO categoryDTO);
/**
* 分页查询
* @param categoryPageQueryDTO
* @return
*/
PageResult pageQuery(CategoryPageQueryDTO categoryPageQueryDTO);
/**
* 根据id删除分类
* @param id
*/
void deleteById(Long id);
/**
* 修改分类
* @param categoryDTO
*/
void update(CategoryDTO categoryDTO);
/**
* 启用、禁用分类
* @param status
* @param id
*/
void startOrStop(Integer status, Long id);
/**
* 根据类型查询分类
* @param type
* @return
*/
List<Category> list(Integer type);
}
impl实现类
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeMapper employeeMapper;
/**
* 员工登录
*
* @param employeeLoginDTO
* @return
*/
public Employee login(EmployeeLoginDTO employeeLoginDTO) {
String username = employeeLoginDTO.getUsername();
String password = employeeLoginDTO.getPassword();
//1、根据用户名查询数据库中的数据
Employee employee = employeeMapper.getByUsername(username);
//2、处理各种异常情况(用户名不存在、密码不对、账号被锁定)
if (employee == null) {
//账号不存在
throw new AccountNotFoundException(MessageConstant.ACCOUNT_NOT_FOUND);
}
//密码比对
// TODO 后期需要进行md5加密,然后再进行比对
password = DigestUtils.md5DigestAsHex(password.getBytes());
if (!password.equals(employee.getPassword())) {
//密码错误
throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
}
if (employee.getStatus() == StatusConstant.DISABLE) {
//账号被锁定
throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED);
}
//3、返回实体对象
return employee;
}
/**
* 新增员工
*
* @param employeeDTO
*/
public void save(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
//对象属性拷贝
BeanUtils.copyProperties(employeeDTO, employee);
//设置账号的状态,默认正常状态 1表示正常 0表示锁定
employee.setStatus(StatusConstant.ENABLE);
//设置密码,默认密码123456
employee.setPassword(DigestUtils.md5DigestAsHex(PasswordConstant.DEFAULT_PASSWORD.getBytes()));
//设置当前记录的创建时间和修改时间
employee.setCreateTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
//设置当前记录创建人id和修改人id
employee.setCreateUser(BaseContext.getCurrentId());//目前写个假数据,后期修改
employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.insert(employee);
}
/**
* 分页查询
*
* @param employeePageQueryDTO
* @return
*/
public PageResult pageQuery(EmployeePageQueryDTO employeePageQueryDTO) {
// select * from employee limit 0,10
//开始分页查询
PageHelper.startPage(employeePageQueryDTO.getPage(), employeePageQueryDTO.getPageSize());
Page<Employee> page = employeeMapper.pageQuery(employeePageQueryDTO);
long total = page.getTotal();
List<Employee> records = page.getResult();
return new PageResult(total, records);
}
/**
* 启用禁用员工账号
*
* @param status
* @param id
*/
public void startOrStop(Integer status, Long id) {
Employee employee = Employee.builder()
.status(status)
.id(id)
.build();
employeeMapper.update(employee);
}
/**
* 根据id查询员工
*
* @param id
* @return
*/
public Employee getById(Long id) {
Employee employee = employeeMapper.getById(id);
employee.setPassword("****");
return employee;
}
/**
* 编辑员工信息
*
* @param employeeDTO
*/
public void update(EmployeeDTO employeeDTO) {
Employee employee = new Employee();
BeanUtils.copyProperties(employeeDTO, employee);
employee.setUpdateTime(LocalDateTime.now());
employee.setUpdateUser(BaseContext.getCurrentId());
employeeMapper.update(employee);
}
}
Mapper层
@Mapper
public interface DishMapper {
/**
* 根据分类id查询菜品数量
* @param categoryId
* @return
*/
@Select("select count(id) from dish where category_id = #{categoryId}")
Integer countByCategoryId(Long categoryId);
}
@Mapper
public interface SetmealMapper {
/**
* 根据分类id查询套餐的数量
* @param id
* @return
*/
@Select("select count(id) from setmeal where category_id = #{categoryId}")
Integer countByCategoryId(Long id);
}
@Mapper
public interface CategoryMapper {
/**
* 插入数据
* @param category
*/
@Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, update_user)" +
" VALUES" +
" (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")
void insert(Category category);
/**
* 分页查询
* @param categoryPageQueryDTO
* @return
*/
Page<Category> pageQuery(CategoryPageQueryDTO categoryPageQueryDTO);
/**
* 根据id删除分类
* @param id
*/
@Delete("delete from category where id = #{id}")
void deleteById(Long id);
/**
* 根据id修改分类
* @param category
*/
void update(Category category);
/**
* 根据类型查询分类
* @param type
* @return
*/
List<Category> list(Integer type);
}
categoryMapper.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.sky.mapper.CategoryMapper">
<select id="pageQuery" resultType="com.sky.entity.Category">
select * from category
<where>
<if test="name != null and name != ''">
and name like concat('%',#{name},'%')
</if>
<if test="type != null">
and type = #{type}
</if>
</where>
order by sort asc , create_time desc
</select>
<update id="update" parameterType="Category">
update category
<set>
<if test="type != null">
type = #{type},
</if>
<if test="name != null">
name = #{name},
</if>
<if test="sort != null">
sort = #{sort},
</if>
<if test="status != null">
status = #{status},
</if>
<if test="updateTime != null">
update_time = #{updateTime},
</if>
<if test="updateUser != null">
update_user = #{updateUser}
</if>
</set>
where id = #{id}
</update>
<select id="list" resultType="Category">
select * from category
where status = 1
<if test="type != null">
and type = #{type}
</if>
order by sort asc,create_time desc
</select>
</mapper>
一个功能模块实现 往往是 controller层 到 service层 到 serviceImpl 层 到mapper层
底层还是sql实现 按公式做题
有创新 的思维写代码自然更好