parent
d4a5a30c4e
commit
58ad52091f
@ -1,18 +0,0 @@
|
||||
package com.zyx.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/15 07:58
|
||||
*/
|
||||
@RestController
|
||||
public class HelloController {
|
||||
|
||||
@GetMapping("/hello")
|
||||
public String hello() {
|
||||
return "Hello Jenkins";
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,13 @@
|
||||
package com.zyx;
|
||||
package com.zyx.mpdemo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/15 07:56
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class HelloApp {
|
||||
public class MpDemoApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HelloApp.class, args);
|
||||
SpringApplication.run(MpDemoApp.class, args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.zyx.mpdemo.common.exception;
|
||||
|
||||
|
||||
import com.zyx.mpdemo.common.constant.ResponseCode;
|
||||
import com.zyx.mpdemo.common.exception.base.BaseException;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/1 08:17
|
||||
*/
|
||||
public class BusinessException extends BaseException {
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BusinessException() {
|
||||
super(ResponseCode.RESPONSE_CODE_500, "内部系统错误");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package com.zyx.mpdemo.common.exception.base;
|
||||
|
||||
|
||||
import com.zyx.mpdemo.common.constant.ResponseCode;
|
||||
|
||||
/**
|
||||
* <p>自定义异常基类
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/1 08:13
|
||||
*/
|
||||
public abstract class BaseException extends RuntimeException {
|
||||
|
||||
private int code = ResponseCode.RESPONSE_CODE_200;
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BaseException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BaseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public BaseException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public BaseException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public BaseException(String message, Throwable cause,
|
||||
boolean enableSuppression,
|
||||
boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.zyx.mpdemo.common.exception.code;
|
||||
|
||||
/**
|
||||
* <p>封装Response的错误码
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/7 15:35
|
||||
*/
|
||||
public interface IErrorCode {
|
||||
|
||||
Integer getCode();
|
||||
String getMessage();
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.zyx.mpdemo.common.exception.code;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* 枚举常用Response操作码
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum ResultCode implements IErrorCode {
|
||||
|
||||
SUCCESS(HttpStatus.OK.value(), "操作成功!"),
|
||||
FAILED(HttpStatus.INTERNAL_SERVER_ERROR.value(), "操作失败!"),
|
||||
|
||||
AUTHENTICATION_FAILED(50001, "获取token失败!"),
|
||||
AUTH_SERVER_ERROR(50002, "授权服务异常!"),
|
||||
LOGIN_METHOD_IS_EMPTY(50003, "登录方式不能为空!"),
|
||||
LOGIN_METHOD_IS_INVALID(50004, "登录方式只支持password模式!"),
|
||||
|
||||
UNAUTHORIZED(40001, "身份认证失败!"),
|
||||
VALIDATE_FAILED(40002, "Token参数校验失败,请检查Token是否正确!"),
|
||||
FORBIDDEN(40003, "无权限请求,请检测当前用户身份信息!"),
|
||||
ACCOUNT_IS_EMPTY(40004, "账号不能为空!"),
|
||||
PASSWORD_IS_EMPTY(40005, "密码不能为空!");
|
||||
|
||||
/**
|
||||
* 消息码
|
||||
*/
|
||||
private final Integer code;
|
||||
|
||||
/**
|
||||
* 消息体
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
@Override
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
package com.zyx.mpdemo.common.resp;
|
||||
|
||||
import com.zyx.mpdemo.common.exception.code.IErrorCode;
|
||||
import com.zyx.mpdemo.common.exception.code.ResultCode;
|
||||
import com.zyx.mpdemo.common.resp.base.BaseResponse;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/1 08:32
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class CommonResponse<T> extends BaseResponse implements Serializable {
|
||||
|
||||
private T data;
|
||||
|
||||
public CommonResponse(Integer code, String message) {
|
||||
this(code, message, null);
|
||||
}
|
||||
|
||||
public CommonResponse(Integer code, String message, T data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> success(T data) {
|
||||
return new CommonResponse<>(ResultCode.SUCCESS.getCode(), ResultCode.SUCCESS.getMessage(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> success(T data, String message) {
|
||||
return new CommonResponse<>(ResultCode.SUCCESS.getCode(), message, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> failed(IErrorCode errorCode) {
|
||||
return new CommonResponse<>(errorCode.getCode(), errorCode.getMessage(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> failed(IErrorCode errorCode, String message) {
|
||||
return new CommonResponse<>(errorCode.getCode(), message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> failed(String message) {
|
||||
return new CommonResponse<>(ResultCode.FAILED.getCode(), message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> failed(Integer code, String message) {
|
||||
return new CommonResponse<>(code, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> failed() {
|
||||
return failed(ResultCode.FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数验证失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> validateFailed() {
|
||||
return failed(ResultCode.VALIDATE_FAILED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数验证失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> validateFailed(String message) {
|
||||
return new CommonResponse<>(ResultCode.VALIDATE_FAILED.getCode(),
|
||||
String.format("%s,%s", message, ResultCode.VALIDATE_FAILED.getMessage()), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 身份验证失败返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> authenticationFailed(String message) {
|
||||
return new CommonResponse<T>(ResultCode.AUTHENTICATION_FAILED.getCode(),
|
||||
String.format("%s,%s", message, ResultCode.AUTHENTICATION_FAILED.getMessage()), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Token已经过期
|
||||
*/
|
||||
public static <T> CommonResponse<T> authenticationExpired(String message) {
|
||||
return new CommonResponse<>(ResultCode.UNAUTHORIZED.getCode(), String.format("%s,%s", message, ResultCode.UNAUTHORIZED.getMessage()), null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Token无效返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> unauthorized(T data) {
|
||||
return new CommonResponse<>(ResultCode.UNAUTHORIZED.getCode(), ResultCode.UNAUTHORIZED.getMessage(), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 未授权返回结果
|
||||
*/
|
||||
public static <T> CommonResponse<T> forbidden(T data) {
|
||||
return new CommonResponse<>(ResultCode.FORBIDDEN.getCode(), ResultCode.FORBIDDEN.getMessage(), data);
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.zyx.mpdemo.common.resp.base;
|
||||
|
||||
|
||||
import com.zyx.mpdemo.common.constant.ResponseCode;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/1 08:32
|
||||
*/
|
||||
@Data
|
||||
public class BaseResponse {
|
||||
|
||||
protected int code = ResponseCode.RESPONSE_CODE_200;
|
||||
protected String message;
|
||||
|
||||
public BaseResponse() {
|
||||
}
|
||||
|
||||
public BaseResponse(int status, String message) {
|
||||
this.code = status;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.zyx.mpdemo.config;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>MyBatisPlus自动填充
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/11/21 10:27
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
// log.info("start insert fill ....");
|
||||
this.strictInsertFill(metaObject, "createTime", Date.class, Calendar.getInstance().getTime()); // 起始版本 3.3.0(推荐使用)
|
||||
this.strictInsertFill(metaObject, "updateTime", Date.class, Calendar.getInstance().getTime()); // 起始版本 3.3.0(推荐使用)
|
||||
// 或者
|
||||
// this.strictInsertFill(metaObject, "createTime", () -> Calendar.getInstance().getTime(), Date.class); // 起始版本 3.3.3(推荐)
|
||||
// 或者
|
||||
// this.fillStrategy(metaObject, "createTime", Calendar.getInstance().getTime()); // 也可以使用(3.3.0 该方法有bug)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
// log.info("start update fill ....");
|
||||
this.strictUpdateFill(metaObject, "updateTime", Date.class, Calendar.getInstance().getTime()); // 起始版本 3.3.0(推荐)
|
||||
// 或者
|
||||
// this.strictUpdateFill(metaObject, "updateTime", () -> Calendar.getInstance().getTime(), Date.class); // 起始版本 3.3.3(推荐)
|
||||
// 或者
|
||||
// this.fillStrategy(metaObject, "updateTime", Calendar.getInstance().getTime()); // 也可以使用(3.3.0 该方法有bug)
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.zyx.mpdemo.config;
|
||||
|
||||
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/3/28 18:09
|
||||
* reference: https://www.cxyzjd.com/article/qq_39720208/104631573
|
||||
*/
|
||||
|
||||
@Component
|
||||
@ConfigurationPropertiesBinding
|
||||
public class ObjectWrapperFactoryConverter implements Converter<String,ObjectWrapperFactory> {
|
||||
@Override
|
||||
public ObjectWrapperFactory convert(String source) {
|
||||
try {
|
||||
return (ObjectWrapperFactory) Class.forName(source).newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package com.zyx.mpdemo.controller;
|
||||
|
||||
import com.zyx.mpdemo.common.resp.CommonResponse;
|
||||
import com.zyx.mpdemo.model.req.BatchLearnedReq;
|
||||
import com.zyx.mpdemo.model.req.CourseDetailReq;
|
||||
import com.zyx.mpdemo.model.req.CourseListReq;
|
||||
import com.zyx.mpdemo.model.vo.CourseDetailVO;
|
||||
import com.zyx.mpdemo.model.vo.CourseInfoVO;
|
||||
import com.zyx.mpdemo.model.vo.CourseListVO;
|
||||
import com.zyx.mpdemo.service.ICourseService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 课程相关接口
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 08:52
|
||||
*/
|
||||
@Slf4j
|
||||
@Controller
|
||||
@ResponseBody
|
||||
@RequestMapping("/course")
|
||||
public class CourseController {
|
||||
|
||||
@Resource
|
||||
private ICourseService courseService;
|
||||
|
||||
/**
|
||||
* 查询所有课程名称以及章节号
|
||||
*
|
||||
* @return 所有课程名称以及章节号
|
||||
*/
|
||||
@GetMapping("/course-infos")
|
||||
public CommonResponse<List<CourseInfoVO>> getCourseInfo() {
|
||||
return CommonResponse.success(courseService.getCourseInfo(), "查询所有课程名称以及章节号成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 依据课程id查询课程列表
|
||||
*/
|
||||
@PostMapping("/course-list")
|
||||
public CommonResponse<CourseListVO> getCourseList(@Validated @RequestBody CourseListReq courseListReq) {
|
||||
return CommonResponse.success(courseService.getCourseList(courseListReq), "查询课程列表成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询课程详情
|
||||
*/
|
||||
@PostMapping("/course-detail")
|
||||
public CommonResponse<List<CourseDetailVO>> getCourseDetail(@Validated @RequestBody CourseDetailReq courseDetailReq) {
|
||||
return CommonResponse.success(courseService.getCourseDetail(courseDetailReq), "查询课程详情成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量修改课程为已学完
|
||||
*/
|
||||
@PutMapping("/batch-learned")
|
||||
public CommonResponse<Void> batchLearned(@Validated @RequestBody BatchLearnedReq batchLearnedReq) {
|
||||
courseService.batchLearned(batchLearnedReq);
|
||||
return CommonResponse.success(null, "批量修改课程为已学完成功");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package com.zyx.mpdemo.helpers.handler;
|
||||
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.zyx.mpdemo.common.constant.ResponseCode;
|
||||
import com.zyx.mpdemo.common.exception.BusinessException;
|
||||
import com.zyx.mpdemo.common.exception.code.ResultCode;
|
||||
import com.zyx.mpdemo.common.resp.CommonResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>全局异常捕获
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/10/1 08:27
|
||||
*/
|
||||
@Slf4j
|
||||
@ControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ResponseBody
|
||||
@ExceptionHandler(value = Exception.class)
|
||||
public CommonResponse<Void> invalidCommon(Exception ex) {
|
||||
log.error("全局异常捕获", ex);
|
||||
return new CommonResponse<>(ResponseCode.RESPONSE_CODE_500, "全局异常捕获:" + ex.getMessage(), null);
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
@ExceptionHandler(value = BusinessException.class)
|
||||
public CommonResponse<Void> invalidBusiness(BusinessException ex) {
|
||||
log.error("业务异常捕获", ex);
|
||||
return new CommonResponse<>(ex.getCode(), ex.getMessage(), null);
|
||||
}
|
||||
|
||||
|
||||
@ResponseBody
|
||||
@ExceptionHandler(value = MethodArgumentNotValidException.class)
|
||||
public CommonResponse<Void> methodArgumentNotValidException(MethodArgumentNotValidException ex) {
|
||||
log.error("全局异常捕获", ex);
|
||||
List<ObjectError> allErrors = ex.getBindingResult().getAllErrors();
|
||||
String errorStr = "";
|
||||
if (CollUtil.isNotEmpty(allErrors)) {
|
||||
errorStr = allErrors.stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining(","));
|
||||
}
|
||||
Executable executable = ex.getParameter().getParameter().getDeclaringExecutable();
|
||||
if (Objects.nonNull(executable)) {
|
||||
String clazz = executable.getDeclaringClass().getName();
|
||||
String method = executable.getName();
|
||||
log.error("{}#{} 参数校验失败: [{}]", clazz, method, errorStr);
|
||||
}
|
||||
return new CommonResponse<>(ResultCode.FAILED.getCode(), "参数校验失败:" + errorStr, null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package com.zyx.mpdemo.helpers.injector;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
|
||||
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>mybatis-plus添加SQL注入器
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/12/7 10:40
|
||||
*/
|
||||
public class EasySqlInjector extends DefaultSqlInjector {
|
||||
@Override
|
||||
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
|
||||
// 注意:此SQL注入器继承了DefaultSqlInjector(默认注入器)
|
||||
// 调用了DefaultSqlInjector的getMethodList方法,保留了mybatis-plus的自带方法
|
||||
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
|
||||
methodList.add(new InsertBatchSomeColumn());
|
||||
return methodList;
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package com.zyx.mpdemo.helpers.utils;
|
||||
|
||||
import com.zyx.mpdemo.model.entity.Course;
|
||||
import com.zyx.mpdemo.model.vo.CourseCost;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>课程统计工具类
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/11/21 14:23
|
||||
*/
|
||||
public class CourseStatisticsUtils {
|
||||
|
||||
/**
|
||||
* 依据课程列表获取课程时间
|
||||
*/
|
||||
public static CourseCost getCourseCost(List<Course> courses) {
|
||||
List<CourseCost> courseCostList = courses.stream()
|
||||
.map(it -> new CourseCost().setHours(it.getCourseHours()).setMinutes(it.getCourseMinutes()).setSeconds(it.getCourseSeconds()))
|
||||
.collect(Collectors.toList());
|
||||
return CourseCost.fromList(courseCostList);
|
||||
}
|
||||
|
||||
public static double getLearnedPercentage(CourseCost learnedCourse, CourseCost allCourse) {
|
||||
return learnedCourse.getCourseSeconds() * 1.0 / allCourse.getCourseSeconds();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.zyx.mpdemo.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.zyx.mpdemo.model.entity.Course;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>针对表【t_course】的数据库操作Mapper
|
||||
*
|
||||
* @author zhangyaxi
|
||||
* @since 2022-11-21 12:12
|
||||
*/
|
||||
@Mapper
|
||||
public interface CourseMapper extends BaseMapper<Course> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
package com.zyx.mpdemo.mapper;
|
||||
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.zyx.mpdemo.model.entity.Product;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* Date:2022/2/15
|
||||
* Author:ybc
|
||||
* Description:
|
||||
*/
|
||||
@Repository
|
||||
public interface ProductMapper extends BaseMapper<Product> {
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.zyx.mpdemo.mapper.base;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* <p>EasyBaseMapper接口,添加insertBatchSomeColumn批量插入方法
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/12/7 10:45
|
||||
*/
|
||||
public interface EasyBaseMapper<T> extends BaseMapper<T> {
|
||||
/**
|
||||
* 批量插入 仅适用于 mysql
|
||||
*
|
||||
* @param entityList 实体列表
|
||||
* @return 影响行数
|
||||
*/
|
||||
Integer insertBatchSomeColumn(Collection<T> entityList);
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package com.zyx.mpdemo.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.zyx.mpdemo.model.enums.CourseStatusEnums;
|
||||
import com.zyx.mpdemo.model.vo.CourseVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>t_course对应实体类
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/11/21 12:13
|
||||
*/
|
||||
@TableName(value ="t_course")
|
||||
@Data
|
||||
public class Course implements Serializable {
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 课程id
|
||||
*/
|
||||
private Long courseId;
|
||||
|
||||
/**
|
||||
* 课程名称
|
||||
*/
|
||||
private String courseName;
|
||||
|
||||
/**
|
||||
* 课程章节
|
||||
*/
|
||||
private String chapter;
|
||||
|
||||
/**
|
||||
* 课程序号数
|
||||
*/
|
||||
private String sequence;
|
||||
|
||||
/**
|
||||
* 课程小时数
|
||||
*/
|
||||
private Integer courseHours;
|
||||
|
||||
/**
|
||||
* 课程分钟数
|
||||
*/
|
||||
private Integer courseMinutes;
|
||||
|
||||
/**
|
||||
* 课程秒数
|
||||
*/
|
||||
private Integer courseSeconds;
|
||||
|
||||
/**
|
||||
* 课程状态
|
||||
*/
|
||||
private CourseStatusEnums courseStatus;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
|
||||
public CourseVO toCourseVO() {
|
||||
CourseVO courseVO = new CourseVO();
|
||||
courseVO.setId(this.id);
|
||||
courseVO.setCourseId(this.courseId);
|
||||
courseVO.setCourseName(this.courseName);
|
||||
courseVO.setChapter(this.chapter);
|
||||
courseVO.setSequence(this.sequence);
|
||||
courseVO.setCourseHours(this.courseHours);
|
||||
courseVO.setCourseMinutes(this.courseMinutes);
|
||||
courseVO.setCourseSeconds(this.courseSeconds);
|
||||
courseVO.setCourseStatus(this.courseStatus.getDesc());
|
||||
return courseVO;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.zyx.mpdemo.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.Version;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/3/29 14:06
|
||||
*/
|
||||
@Data
|
||||
@TableName("t_product")
|
||||
public class Product {
|
||||
private Long id;
|
||||
private String name;
|
||||
private Integer price;
|
||||
/** 标识乐观锁版本号字段 */
|
||||
@Version
|
||||
private Integer version;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package com.zyx.mpdemo.model.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/3/28 10:03
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("t_user")
|
||||
public class User {
|
||||
|
||||
// 将属性所对应的字段指定为主键
|
||||
// @TableId注解的value属性用于指定主键的字段
|
||||
// @TableId注解的type属性设置主键生成策略
|
||||
// @TableId(value = "uid", type = IdType.AUTO)
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
// 指定属性所对应的字段名
|
||||
// @TableField("user_name")
|
||||
private String name;
|
||||
|
||||
private Integer age;
|
||||
|
||||
private String email;
|
||||
|
||||
// private SexEnum sex;
|
||||
|
||||
// @TableLogic
|
||||
// private Integer isDeleted;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package com.zyx.mpdemo.model.enums;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* <p>课程状态枚举
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/11/21 11:36
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CourseStatusEnums {
|
||||
DELETE(0, "删除"),
|
||||
LEARNING(1, "未学习"),
|
||||
LEARNED(2, "已学习"),
|
||||
;
|
||||
|
||||
@EnumValue
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
|
||||
public static CourseStatusEnums of(Integer code) {
|
||||
Objects.requireNonNull(code);
|
||||
return Stream.of(values())
|
||||
.filter(it -> it.getCode().equals(code))
|
||||
.findAny()
|
||||
.orElseThrow(() -> new IllegalArgumentException(code + " not exists"));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package com.zyx.mpdemo.model.enums;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/3/28 10:12
|
||||
*/
|
||||
@Getter
|
||||
public enum SexEnum {
|
||||
/** 性别 */
|
||||
MALE(1, "男"),
|
||||
FEMALE(2, "女");
|
||||
|
||||
/**
|
||||
* 将注解所标识的属性的值存储到数据库中
|
||||
* 注意: 配置文件中需要配置 type-enums-package ,指定枚举类所在包
|
||||
*/
|
||||
@EnumValue
|
||||
private final Integer sex;
|
||||
private final String sexName;
|
||||
|
||||
SexEnum(Integer sex, String sexName) {
|
||||
this.sex = sex;
|
||||
this.sexName = sexName;
|
||||
}
|
||||
|
||||
public static SexEnum getSexEnumByCode(Integer sex) {
|
||||
return Stream.of(values()).filter(item -> item.sex.equals(sex)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package com.zyx.mpdemo.model.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 10:33
|
||||
*/
|
||||
@Data
|
||||
public class BatchLearnedReq {
|
||||
|
||||
@NotNull(message = "课程名称不能为空")
|
||||
private String courseName;
|
||||
|
||||
@NotNull(message = "章节不能为空")
|
||||
private String chapter;
|
||||
|
||||
@NotNull(message = "开始序号不能为空")
|
||||
private String startSeq;
|
||||
|
||||
@NotNull(message = "结束序号不能为空")
|
||||
private String endSeq;
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.zyx.mpdemo.model.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 10:01
|
||||
*/
|
||||
@Data
|
||||
public class CourseDetailReq {
|
||||
|
||||
@NotNull(message = "课程名称不能为空")
|
||||
private String courseName;
|
||||
|
||||
/**
|
||||
* 返回时是否需要按章节划分
|
||||
*/
|
||||
private boolean needChapter = false;
|
||||
|
||||
/**
|
||||
* 只查询指定章节的信息
|
||||
*/
|
||||
private Set<String> chapters;
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.zyx.mpdemo.model.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 13:05
|
||||
*/
|
||||
@Data
|
||||
public class CourseListReq {
|
||||
|
||||
@NotNull(message = "课程id不能为空")
|
||||
private Long courseId;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String chapter;
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.zyx.mpdemo.model.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>课程耗时
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/11/21 14:20
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CourseCost {
|
||||
/** 小时数 */
|
||||
private Integer hours;
|
||||
|
||||
/** 分钟数 */
|
||||
private Integer minutes;
|
||||
|
||||
/** 秒数 */
|
||||
private Integer seconds;
|
||||
|
||||
/** 获取课程秒数 */
|
||||
public Integer getCourseSeconds() {
|
||||
return this.hours * 60 * 60 + this.minutes * 60 + this.seconds;
|
||||
}
|
||||
|
||||
/** 通过总的小时数、分钟数以及秒数获取实际课程耗时 */
|
||||
public static CourseCost fromAll(Integer allHours, Integer allMinutes, Integer allSeconds) {
|
||||
allMinutes += allSeconds / 60;
|
||||
allSeconds = allSeconds % 60;
|
||||
allHours += allMinutes / 60;
|
||||
allMinutes = allMinutes % 60;
|
||||
return new CourseCost().setHours(allHours).setMinutes(allMinutes).setSeconds(allSeconds);
|
||||
}
|
||||
|
||||
/** 通过课程耗时列表获取实际课程耗时 */
|
||||
public static CourseCost fromList(List<CourseCost> courseCostList) {
|
||||
Integer hours = 0;
|
||||
Integer minutes = 0;
|
||||
Integer seconds = 0;
|
||||
for (CourseCost courseCost : courseCostList) {
|
||||
hours += courseCost.getHours();
|
||||
minutes += courseCost.getMinutes();
|
||||
seconds += courseCost.getSeconds();
|
||||
}
|
||||
return fromAll(hours, minutes, seconds);
|
||||
}
|
||||
|
||||
/** 通过总秒数获取CourseCost */
|
||||
public static CourseCost secondToCourseCost(int seconds) {
|
||||
int hour = seconds / 3600;
|
||||
int other = seconds % 3600;
|
||||
int minute = other / 60;
|
||||
int second = other % 60;
|
||||
return new CourseCost().setHours(hour).setMinutes(minute).setSeconds(second);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package com.zyx.mpdemo.model.vo;
|
||||
|
||||
import com.zyx.mpdemo.helpers.utils.CourseStatisticsUtils;
|
||||
import com.zyx.mpdemo.model.entity.Course;
|
||||
import com.zyx.mpdemo.model.enums.CourseStatusEnums;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 课程详情
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 10:02
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CourseDetailVO {
|
||||
|
||||
private String courseName;
|
||||
private String chapter;
|
||||
private CourseCost allCost;
|
||||
private CourseCost learnedCost;
|
||||
private CourseCost learningCost;
|
||||
private String learnedPercentage;
|
||||
|
||||
public static CourseDetailVO getCourseDetail(String courseName, String chapter, List<Course> courses) {
|
||||
List<Course> learned = courses.stream()
|
||||
.filter(it -> Objects.equals(it.getCourseStatus(), CourseStatusEnums.LEARNED)).collect(Collectors.toList());
|
||||
List<Course> learning = courses.stream()
|
||||
.filter(it -> Objects.equals(it.getCourseStatus(), CourseStatusEnums.LEARNING)).collect(Collectors.toList());
|
||||
CourseCost allCost = CourseStatisticsUtils.getCourseCost(courses);
|
||||
CourseCost learnedCost = CourseStatisticsUtils.getCourseCost(learned);
|
||||
CourseCost learningCost = CourseStatisticsUtils.getCourseCost(learning);
|
||||
double learnedPercentageDouble = CourseStatisticsUtils.getLearnedPercentage(learnedCost, allCost);
|
||||
String learnedPercentage = String.format("%.2f%%", learnedPercentageDouble * 100);
|
||||
return new CourseDetailVO()
|
||||
.setCourseName(courseName)
|
||||
.setChapter(chapter)
|
||||
.setAllCost(allCost)
|
||||
.setLearnedCost(learnedCost)
|
||||
.setLearningCost(learningCost)
|
||||
.setLearnedPercentage(learnedPercentage);
|
||||
}
|
||||
|
||||
public static List<CourseDetailVO> getCourseDetails(String courseName, List<Course> allCourses) {
|
||||
List<CourseDetailVO> courseDetails = new ArrayList<>();
|
||||
Map<String, List<Course>> courseMap = new HashMap<>();
|
||||
List<String> chapters = new ArrayList<>();
|
||||
allCourses.forEach(course->{
|
||||
String chapter = course.getChapter();
|
||||
if (!chapters.contains(chapter)) {
|
||||
chapters.add(course.getChapter());
|
||||
List<Course> courseList = new ArrayList<>();
|
||||
courseList.add(course);
|
||||
courseMap.put(chapter, courseList);
|
||||
} else {
|
||||
courseMap.get(chapter).add(course);
|
||||
}
|
||||
});
|
||||
for (String chapter : chapters) {
|
||||
List<Course> courses = courseMap.get(chapter);
|
||||
courseDetails.add(getCourseDetail(courseName, chapter, courses));
|
||||
}
|
||||
return courseDetails;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.zyx.mpdemo.model.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 课程详情
|
||||
*
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 09:18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CourseInfoVO {
|
||||
|
||||
/**
|
||||
* 课程id
|
||||
*/
|
||||
private Long courseId;
|
||||
|
||||
/**
|
||||
* 课程名称
|
||||
*/
|
||||
private String courseName;
|
||||
|
||||
/**
|
||||
* 章节名称
|
||||
*/
|
||||
private Set<String> chapters;
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.zyx.mpdemo.model.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 10:56
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CourseListVO {
|
||||
|
||||
private Long courseId;
|
||||
private String courseName;
|
||||
/**
|
||||
* (章节名称, 课程列表)
|
||||
*/
|
||||
private Map<String, List<CourseVO>> courseMap;
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package com.zyx.mpdemo.model.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2023/1/26 10:51
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class CourseVO {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 课程id
|
||||
*/
|
||||
private Long courseId;
|
||||
|
||||
/**
|
||||
* 课程名称
|
||||
*/
|
||||
private String courseName;
|
||||
|
||||
/**
|
||||
* 课程章节
|
||||
*/
|
||||
private String chapter;
|
||||
|
||||
/**
|
||||
* 课程序号数
|
||||
*/
|
||||
private String sequence;
|
||||
|
||||
/**
|
||||
* 课程小时数
|
||||
*/
|
||||
private Integer courseHours;
|
||||
|
||||
/**
|
||||
* 课程分钟数
|
||||
*/
|
||||
private Integer courseMinutes;
|
||||
|
||||
/**
|
||||
* 课程秒数
|
||||
*/
|
||||
private Integer courseSeconds;
|
||||
|
||||
/**
|
||||
* 课程状态
|
||||
*/
|
||||
private String courseStatus;
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.zyx.mpdemo.model.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/3/29 09:46
|
||||
*/
|
||||
@Data
|
||||
public class PartUser {
|
||||
private String userName;
|
||||
private Integer age;
|
||||
private String email;
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.zyx.mpdemo.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.zyx.mpdemo.model.entity.Course;
|
||||
import com.zyx.mpdemo.model.req.BatchLearnedReq;
|
||||
import com.zyx.mpdemo.model.req.CourseDetailReq;
|
||||
import com.zyx.mpdemo.model.req.CourseListReq;
|
||||
import com.zyx.mpdemo.model.vo.CourseDetailVO;
|
||||
import com.zyx.mpdemo.model.vo.CourseInfoVO;
|
||||
import com.zyx.mpdemo.model.vo.CourseListVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>针对表【t_course】的数据库操作Service</p>
|
||||
*
|
||||
* @author zhangyaxi
|
||||
* @since 2022-11-21 12:12
|
||||
*/
|
||||
public interface ICourseService extends IService<Course> {
|
||||
|
||||
/**
|
||||
* 查询课程信息
|
||||
*/
|
||||
List<CourseInfoVO> getCourseInfo();
|
||||
|
||||
/**
|
||||
* 查询课程详情
|
||||
*/
|
||||
List<CourseDetailVO> getCourseDetail(CourseDetailReq courseDetailReq);
|
||||
|
||||
/**
|
||||
* 批量修改课程为已学完
|
||||
*/
|
||||
void batchLearned(BatchLearnedReq batchLearnedReq);
|
||||
|
||||
/**
|
||||
* 依据课程id查询课程列表
|
||||
*/
|
||||
CourseListVO getCourseList(CourseListReq courseListReq);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.zyx.mpdemo.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.zyx.mpdemo.model.entity.User;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/3/28 17:09
|
||||
*/
|
||||
public interface IUserService extends IService<User> {
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.zyx.mpdemo.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.zyx.mpdemo.common.exception.BusinessException;
|
||||
import com.zyx.mpdemo.mapper.CourseMapper;
|
||||
import com.zyx.mpdemo.model.entity.Course;
|
||||
import com.zyx.mpdemo.model.enums.CourseStatusEnums;
|
||||
import com.zyx.mpdemo.model.req.BatchLearnedReq;
|
||||
import com.zyx.mpdemo.model.req.CourseDetailReq;
|
||||
import com.zyx.mpdemo.model.req.CourseListReq;
|
||||
import com.zyx.mpdemo.model.vo.CourseDetailVO;
|
||||
import com.zyx.mpdemo.model.vo.CourseInfoVO;
|
||||
import com.zyx.mpdemo.model.vo.CourseListVO;
|
||||
import com.zyx.mpdemo.model.vo.CourseVO;
|
||||
import com.zyx.mpdemo.service.ICourseService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* <p>针对表【t_course】的数据库操作Service实现</p>
|
||||
*
|
||||
* @author zhangyaxi
|
||||
* @since 2022-11-21 12:12
|
||||
*/
|
||||
@Service
|
||||
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {
|
||||
|
||||
@Override
|
||||
public List<CourseInfoVO> getCourseInfo() {
|
||||
List<CourseInfoVO> courseInfos = new ArrayList<>();
|
||||
QueryWrapper<Course> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.select("distinct course_id, course_name, chapter")
|
||||
.ne("course_status", CourseStatusEnums.DELETE);
|
||||
List<Course> courses = list(queryWrapper);
|
||||
Map<Long, List<Course>> courseMap = courses.stream().collect(Collectors.groupingBy(Course::getCourseId));
|
||||
List<Long> courseIds = new ArrayList<>(courseMap.keySet());
|
||||
courseIds.sort(Long::compareTo);
|
||||
for (Long courseId : courseIds) {
|
||||
List<Course> coursesById = courseMap.get(courseId);
|
||||
if (CollUtil.isNotEmpty(coursesById)) {
|
||||
String courseName = coursesById.get(0).getCourseName();
|
||||
Set<String> chapters = coursesById.stream().map(Course::getChapter).collect(Collectors.toSet());
|
||||
courseInfos.add(new CourseInfoVO().setCourseId(courseId).setCourseName(courseName).setChapters(chapters));
|
||||
}
|
||||
}
|
||||
return courseInfos;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<CourseDetailVO> getCourseDetail(CourseDetailReq courseDetailReq) {
|
||||
List<CourseDetailVO> courseDetails = new ArrayList<>();
|
||||
String courseName = courseDetailReq.getCourseName();
|
||||
LambdaQueryWrapper<Course> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper
|
||||
.eq(Course::getCourseName, courseName)
|
||||
.ne(Course::getCourseStatus, CourseStatusEnums.DELETE);
|
||||
boolean needChapter = courseDetailReq.isNeedChapter();
|
||||
Set<String> chapters = courseDetailReq.getChapters();
|
||||
if (!needChapter) {
|
||||
// 不需要分组
|
||||
List<Course> courses = list(queryWrapper);
|
||||
courseDetails.add(CourseDetailVO.getCourseDetail(courseName, "all", courses));
|
||||
} else {
|
||||
// 需要分组
|
||||
queryWrapper.in(CollUtil.isNotEmpty(chapters), Course::getChapter, chapters);
|
||||
List<Course> courses = list(queryWrapper);
|
||||
courseDetails.addAll(CourseDetailVO.getCourseDetails(courseName, courses));
|
||||
}
|
||||
return courseDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void batchLearned(BatchLearnedReq batchLearnedReq) {
|
||||
LambdaQueryWrapper<Course> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper
|
||||
.eq(Course::getCourseName, batchLearnedReq.getCourseName())
|
||||
.eq(Course::getChapter, batchLearnedReq.getChapter())
|
||||
.ge(Course::getSequence, batchLearnedReq.getStartSeq())
|
||||
.le(Course::getSequence, batchLearnedReq.getEndSeq())
|
||||
.ne(Course::getCourseStatus, CourseStatusEnums.DELETE);
|
||||
List<Course> updateCourses = list(queryWrapper).stream()
|
||||
.filter(it -> it.getCourseStatus().equals(CourseStatusEnums.LEARNING))
|
||||
.peek(it -> {
|
||||
it.setCourseStatus(CourseStatusEnums.LEARNED);
|
||||
it.setUpdateTime(null);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isEmpty(updateCourses)) {
|
||||
throw new BusinessException("当前课程及章节下不存在未学习的内容");
|
||||
}
|
||||
updateBatchById(updateCourses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseListVO getCourseList(CourseListReq courseListReq) {
|
||||
Long courseId = courseListReq.getCourseId();
|
||||
Integer status = courseListReq.getStatus();
|
||||
String chapter = courseListReq.getChapter();
|
||||
LambdaQueryWrapper<Course> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper
|
||||
.eq(Course::getCourseId, courseId);
|
||||
if (Objects.isNull(status) || Objects.equals(status, 0)) {
|
||||
queryWrapper.ne(Course::getCourseStatus, CourseStatusEnums.DELETE);
|
||||
} else {
|
||||
CourseStatusEnums courseStatus = CourseStatusEnums.of(status);
|
||||
queryWrapper.eq(Course::getCourseStatus, courseStatus);
|
||||
}
|
||||
queryWrapper.eq(StrUtil.isNotEmpty(chapter), Course::getChapter, chapter);
|
||||
List<Course> courses = list(queryWrapper);
|
||||
if (CollUtil.isEmpty(courses)) {
|
||||
throw new BusinessException("不存在当前的课程");
|
||||
}
|
||||
String courseName = courses.get(0).getCourseName();
|
||||
TreeMap<String, List<CourseVO>> courseMap = courses.stream()
|
||||
.map(Course::toCourseVO)
|
||||
.collect(Collectors.groupingBy(CourseVO::getChapter, TreeMap::new, Collectors.toList()));
|
||||
return new CourseListVO().setCourseId(courseId).setCourseName(courseName).setCourseMap(courseMap);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.zyx.mpdemo.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.zyx.mpdemo.mapper.UserMapper;
|
||||
import com.zyx.mpdemo.model.entity.User;
|
||||
import com.zyx.mpdemo.service.IUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author Yaxi.Zhang
|
||||
* @since 2022/3/28 17:10
|
||||
*/
|
||||
@Service
|
||||
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
|
||||
}
|
||||
|
@ -1,2 +1,52 @@
|
||||
server:
|
||||
port: 9001
|
||||
port: 9001
|
||||
spring:
|
||||
application:
|
||||
name: com-zyx-mpdemo
|
||||
jackson:
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
default-property-inclusion: non_null
|
||||
time-zone: GMT+8
|
||||
# 配置数据源信息
|
||||
datasource:
|
||||
type: com.zaxxer.hikari.HikariDataSource
|
||||
# 配置连接数据库信息
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://81.68.117.201:3306/db_test?allowPublicKeyRetrieval=true&allowMultiQueries=true&useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&nullCatalogMeansCurrent=true
|
||||
username: test
|
||||
password: test
|
||||
hikari:
|
||||
pool-name: MpDemoPool
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 5
|
||||
validation-timeout: 2500
|
||||
idle-timeout: 30000
|
||||
max-lifetime: 60000
|
||||
connection-timeout: 30000
|
||||
connection-test-query: SELECT 1
|
||||
|
||||
mybatis-plus:
|
||||
# 设置MyBatis-Plus的全局配置
|
||||
# global-config:
|
||||
# db-config:
|
||||
# # 设置统一的主键生成策略
|
||||
# id-type: auto
|
||||
# # 设置实体类所对应的表的统一前缀
|
||||
# table-prefix: t_
|
||||
configuration:
|
||||
# mybatis日志输出
|
||||
# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
# 开启下划线转驼峰, MyBatisPlus默认是开启的
|
||||
map-underscore-to-camel-case: true
|
||||
# 开启返回map结果集的下划线转驼峰,
|
||||
# https://www.jianshu.com/p/ae9fd5c3169c
|
||||
# 需要配置ObjectWrapperFactoryConverter!!!
|
||||
# 否则报错:
|
||||
# Failed to bind properties under 'mybatis-plus.configuration.object-wrapper-factory' to org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory
|
||||
# object-wrapper-factory: com.baomidou.mybatisplus.extension.MybatisMapWrapperFactory
|
||||
# 配置类型别名所对应的包, mapper.xml的resultType可以直接通过类名使用
|
||||
type-aliases-package: com.zyx.mpdemo.model.entity
|
||||
# 扫描通用枚举的包
|
||||
type-enums-package: com.zyx.mpdemo.model.enums
|
||||
# 默认值为 classpath*:/mapper/**/*.xml, 如果mapper放在其他的位置, 需要自己配置(这里可配可不配)
|
||||
mapper-locations: classpath*:/mapper/**/*.xml
|
@ -0,0 +1,27 @@
|
||||
<?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.zyx.mpdemo.mapper.CourseMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.zyx.mpdemo.model.entity.Course">
|
||||
<id property="id" column="id" jdbcType="BIGINT"/>
|
||||
<result property="courseId" column="course_id" jdbcType="BIGINT"/>
|
||||
<result property="courseName" column="course_name" jdbcType="VARCHAR"/>
|
||||
<result property="chapter" column="chapter" jdbcType="VARCHAR"/>
|
||||
<result property="sequence" column="sequence" jdbcType="VARCHAR"/>
|
||||
<result property="courseHours" column="course_hours" jdbcType="INTEGER"/>
|
||||
<result property="courseMinutes" column="course_minutes" jdbcType="INTEGER"/>
|
||||
<result property="courseSeconds" column="course_seconds" jdbcType="INTEGER"/>
|
||||
<result property="courseStatus" column="course_status" jdbcType="TINYINT"/>
|
||||
<result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
|
||||
<result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,course_id,course_name,
|
||||
chapter,sequence,course_hours,
|
||||
course_minutes,course_seconds,course_status,
|
||||
create_time,update_time
|
||||
</sql>
|
||||
</mapper>
|
@ -0,0 +1,17 @@
|
||||
<?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.zyx.mpdemo.mapper.UserMapper">
|
||||
|
||||
<!--Map<String, Object> selectMapById(Long id);-->
|
||||
<select id="selectMapByAge" resultType="map">
|
||||
select id,user_name,age,email from t_user where age = #{age}
|
||||
</select>
|
||||
|
||||
<!--Page<User> selectPageVo(@Param("page") Page<User> page, @Param("age") Integer age);-->
|
||||
<select id="selectPageVo" resultType="User">
|
||||
select uid,user_name,age,email from t_user where age > #{age}
|
||||
</select>
|
||||
|
||||
</mapper>
|
Loading…
Reference in new issue