commit:支持app的纯后台服务

This commit is contained in:
Jerry
2020-10-29 18:55:12 +08:00
parent dd555d8bb1
commit c87fb476d6
185 changed files with 24073 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package com.orange.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 应用服务启动类。
*
* @author Jerry
* @date 2020-09-24
*/
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

View File

@@ -0,0 +1,58 @@
package com.orange.demo.app.controller;
import io.swagger.annotations.Api;
import cn.jimmyshi.beanquery.BeanQuery;
import com.orange.demo.app.model.AreaCode;
import com.orange.demo.app.service.AreaCodeService;
import com.orange.demo.common.core.object.ResponseResult;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
/**
* 行政区划数据访问接口类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "行政区划数据访问接口")
@RestController
@RequestMapping("/admin/app/areaCode")
public class AreaCodeController {
@Autowired
private AreaCodeService areaCodeService;
/**
* 按照字典的形式返回行政区划列表。
*
* @return 字典形式的行政区划列表。
*/
@GetMapping("/listDictAreaCode")
public ResponseResult<List<Map<String, Object>>> listDictAreaCode() {
List<AreaCode> resultList = areaCodeService.getAllList();
return ResponseResult.success(BeanQuery.select(
"parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList));
}
/**
* 根据上级行政区划Id获取其下级行政区划列表。
*
* @param parentId 上级行政区划Id。
* @return 按照字典的形式返回下级行政区划列表。
*/
@GetMapping("/listDictAreaCodeByParentId")
public ResponseResult<List<Map<String, Object>>> listDictAreaCodeByParentId(@RequestParam(required = false) Long parentId) {
Collection<AreaCode> resultList = areaCodeService.getListByParentId(parentId);
if (CollectionUtils.isEmpty(resultList)) {
return ResponseResult.success(new LinkedList<>());
}
return ResponseResult.success(BeanQuery.select(
"parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList));
}
}

View File

@@ -0,0 +1,290 @@
package com.orange.demo.app.controller;
import cn.jimmyshi.beanquery.BeanQuery;
import cn.hutool.core.util.ReflectUtil;
import com.orange.demo.common.core.upload.BaseUpDownloader;
import com.orange.demo.common.core.upload.UpDownloaderFactory;
import com.orange.demo.common.core.upload.UploadResponseInfo;
import com.orange.demo.common.core.upload.UploadStoreInfo;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.common.core.cache.SessionCacheHelper;
import com.orange.demo.config.ApplicationConfig;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import javax.validation.groups.Default;
/**
* 课程数据操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "课程数据管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/course")
public class CourseController {
@Autowired
private CourseService courseService;
@Autowired
private ApplicationConfig appConfig;
@Autowired
private SessionCacheHelper cacheHelper;
@Autowired
private UpDownloaderFactory upDownloaderFactory;
/**
* 新增课程数据数据。
*
* @param course 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {
"course.courseId",
"course.priceStart",
"course.priceEnd",
"course.classHourStart",
"course.classHourEnd",
"course.createTimeStart",
"course.createTimeEnd"})
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody Course course) {
String errorMessage = MyCommonUtil.getModelValidationError(course);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = courseService.verifyRelatedData(course, null);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
course = courseService.saveNew(course);
return ResponseResult.success(course.getCourseId());
}
/**
* 更新课程数据数据。
*
* @param course 更新对象。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {
"course.priceStart",
"course.priceEnd",
"course.classHourStart",
"course.classHourEnd",
"course.createTimeStart",
"course.createTimeEnd"})
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody Course course) {
String errorMessage = MyCommonUtil.getModelValidationError(course, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
Course originalCourse = courseService.getById(course.getCourseId());
if (originalCourse == null) {
//NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = courseService.verifyRelatedData(course, originalCourse);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
if (!courseService.update(course, originalCourse)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除课程数据数据。
*
* @param courseId 删除对象主键Id。
* @return 应答结果对象。
*/
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long courseId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(courseId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
Course originalCourse = courseService.getById(courseId);
if (originalCourse == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!courseService.remove(courseId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的课程数据列表。
*
* @param courseFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<Course>> list(
@MyRequestBody Course courseFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class);
List<Course> resultList = courseService.getCourseListWithRelation(courseFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定课程数据对象详情。
*
* @param courseId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<Course> view(@RequestParam Long courseId) {
if (MyCommonUtil.existBlankArgument(courseId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
Course course = courseService.getByIdWithRelation(courseId, MyRelationParam.full());
if (course == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(course);
}
/**
* 附件文件下载。
* 这里将图片和其他类型的附件文件放到不同的父目录下,主要为了便于今后图片文件的迁移。
*
* @param courseId 附件所在记录的主键Id。
* @param fieldName 附件所属的字段名。
* @param filename 文件名。如果没有提供该参数,就从当前记录的指定字段中读取。
* @param asImage 下载文件是否为图片。
* @param response Http 应答对象。
*/
@GetMapping("/download")
public void download(
@RequestParam(required = false) Long courseId,
@RequestParam String fieldName,
@RequestParam String filename,
@RequestParam Boolean asImage,
HttpServletResponse response) {
if (MyCommonUtil.existBlankArgument(fieldName, filename, asImage)) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// 使用try来捕获异常是为了保证一旦出现异常可以返回500的错误状态便于调试。
// 否则有可能给前端返回的是200的错误码。
try {
// 如果请求参数中没有包含主键Id就判断该文件是否为当前session上传的。
if (courseId == null) {
if (!cacheHelper.existSessionUploadFile(filename)) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN);
return;
}
} else {
Course course = courseService.getById(courseId);
if (course == null) {
ResponseResult.output(HttpServletResponse.SC_NOT_FOUND);
return;
}
String fieldJsonData = (String) ReflectUtil.getFieldValue(course, fieldName);
if (fieldJsonData == null) {
ResponseResult.output(HttpServletResponse.SC_BAD_REQUEST);
return;
}
if (!BaseUpDownloader.containFile(fieldJsonData, filename)) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN);
return;
}
}
UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(Course.class, fieldName);
if (!storeInfo.isSupportUpload()) {
ResponseResult.output(HttpServletResponse.SC_NOT_IMPLEMENTED,
ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD));
return;
}
BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType());
upDownloader.doDownload(appConfig.getUploadFileBaseDir(),
Course.class.getSimpleName(), fieldName, filename, asImage, response);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
log.error(e.getMessage(), e);
}
}
/**
* 文件上传操作。
*
* @param fieldName 上传文件名。
* @param asImage 是否作为图片上传。如果是图片,今后下载的时候无需权限验证。否则就是附件上传,下载时需要权限验证。
* @param uploadFile 上传文件对象。
*/
@PostMapping("/upload")
public void upload(
@RequestParam String fieldName,
@RequestParam Boolean asImage,
@RequestParam("uploadFile") MultipartFile uploadFile) throws Exception {
UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(Course.class, fieldName);
// 这里就会判断参数中指定的字段,是否支持上传操作。
if (!storeInfo.isSupportUpload()) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN,
ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD));
return;
}
// 根据字段注解中的存储类型,通过工厂方法获取匹配的上传下载实现类,从而解耦。
BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType());
UploadResponseInfo responseInfo = upDownloader.doUpload(null,
appConfig.getUploadFileBaseDir(), Course.class.getSimpleName(), fieldName, asImage, uploadFile);
if (responseInfo.getUploadFailed()) {
ResponseResult.output(HttpServletResponse.SC_FORBIDDEN,
ResponseResult.error(ErrorCodeEnum.UPLOAD_FAILED, responseInfo.getErrorMessage()));
return;
}
cacheHelper.putSessionUploadFile(responseInfo.getFilename());
ResponseResult.output(ResponseResult.success(responseInfo));
}
/**
* 以字典形式返回全部课程数据数据集合。字典的键值为[courseId, courseName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDictCourse")
public ResponseResult<List<Map<String, Object>>> listDictCourse(Course filter) {
List<Course> resultList = courseService.getListByFilter(filter, null);
return ResponseResult.success(BeanQuery.select(
"courseId as id", "courseName as name").executeFrom(resultList));
}
}

View File

@@ -0,0 +1,100 @@
package com.orange.demo.app.controller;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 课程统计操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "课程统计管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/courseTransStats")
public class CourseTransStatsController {
@Autowired
private CourseTransStatsService courseTransStatsService;
/**
* 列出符合过滤条件的课程统计列表。
*
* @param courseTransStatsFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<CourseTransStats>> list(
@MyRequestBody CourseTransStats courseTransStatsFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, CourseTransStats.class);
List<CourseTransStats> resultList = courseTransStatsService.getCourseTransStatsListWithRelation(courseTransStatsFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 分组列出符合过滤条件的课程统计列表。
*
* @param courseTransStatsFilter 过滤对象。
* @param groupParam 分组参数。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/listWithGroup")
public ResponseResult<MyPageData<CourseTransStats>> listWithGroup(
@MyRequestBody CourseTransStats courseTransStatsFilter,
@MyRequestBody MyGroupParam groupParam,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
String orderBy = MyOrderParam.buildOrderBy(orderParam, CourseTransStats.class);
groupParam = MyGroupParam.buildGroupBy(groupParam, CourseTransStats.class);
if (groupParam == null) {
return ResponseResult.error(
ErrorCodeEnum.INVALID_ARGUMENT_FORMAT, "数据参数错误,分组参数不能为空!");
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
MyGroupCriteria criteria = groupParam.getGroupCriteria();
List<CourseTransStats> resultList = courseTransStatsService.getGroupedCourseTransStatsListWithRelation(
courseTransStatsFilter, criteria.getGroupSelect(), criteria.getGroupBy(), orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定课程统计对象详情。
*
* @param statsId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<CourseTransStats> view(@RequestParam Long statsId) {
if (MyCommonUtil.existBlankArgument(statsId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
CourseTransStats courseTransStats = courseTransStatsService.getByIdWithRelation(statsId, MyRelationParam.full());
if (courseTransStats == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(courseTransStats);
}
}

View File

@@ -0,0 +1,115 @@
package com.orange.demo.app.controller;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.constant.ErrorCodeEnum;
import com.orange.demo.common.core.util.MyCommonUtil;
import com.orange.demo.common.core.object.ResponseResult;
import com.orange.demo.common.core.annotation.MyRequestBody;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import cn.jimmyshi.beanquery.BeanQuery;
import javax.validation.groups.Default;
import java.util.*;
/**
* 年级操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "年级管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/grade")
public class GradeController {
@Autowired
private GradeService gradeService;
/**
* 新增年级数据。
*
* @param grade 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"grade.gradeId"})
@PostMapping("/add")
public ResponseResult<Integer> add(@MyRequestBody Grade grade) {
String errorMessage = MyCommonUtil.getModelValidationError(grade);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
grade = gradeService.saveNew(grade);
return ResponseResult.success(grade.getGradeId());
}
/**
* 更新年级数据。
*
* @param grade 更新对象。
* @return 应答结果对象。
*/
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody Grade grade) {
String errorMessage = MyCommonUtil.getModelValidationError(grade, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
Grade originalGrade = gradeService.getById(grade.getGradeId());
if (originalGrade == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
if (!gradeService.update(grade, originalGrade)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除年级数据。
*
* @param gradeId 删除对象主键Id。
* @return 应答结果对象。
*/
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Integer gradeId) {
if (MyCommonUtil.existBlankArgument(gradeId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!gradeService.remove(gradeId)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 以字典形式返回全部年级数据集合。
* 白名单接口,登录用户均可访问。
*
* @return 应答结果对象,包含字典形式的数据集合。
*/
@GetMapping("/listDictGrade")
public ResponseResult<List<Map<String, Object>>> listDictGrade() {
List<Grade> resultList = gradeService.getAllList();
return ResponseResult.success(BeanQuery.select(
"gradeId as id", "gradeName as name").executeFrom(resultList));
}
/**
* 将当前字典表的数据重新加载到缓存中。
* 由于缓存的数据更新在add/update/delete等接口均有同步处理。因此该接口仅当同步过程中出现问题时
* 可手工调用,或者每天晚上定时同步一次。
*/
@GetMapping("/reloadCachedData")
public ResponseResult<Boolean> reloadCachedData() {
gradeService.reloadCachedData(true);
return ResponseResult.success(true);
}
}

View File

@@ -0,0 +1,168 @@
package com.orange.demo.app.controller;
import cn.jimmyshi.beanquery.BeanQuery;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import javax.validation.groups.Default;
/**
* 校区数据操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "校区数据管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/schoolInfo")
public class SchoolInfoController {
@Autowired
private SchoolInfoService schoolInfoService;
/**
* 新增校区数据数据。
*
* @param schoolInfo 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"schoolInfo.userId"})
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody SchoolInfo schoolInfo) {
String errorMessage = MyCommonUtil.getModelValidationError(schoolInfo);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = schoolInfoService.verifyRelatedData(schoolInfo, null);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
schoolInfo = schoolInfoService.saveNew(schoolInfo);
return ResponseResult.success(schoolInfo.getSchoolId());
}
/**
* 更新校区数据数据。
*
* @param schoolInfo 更新对象。
* @return 应答结果对象。
*/
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody SchoolInfo schoolInfo) {
String errorMessage = MyCommonUtil.getModelValidationError(schoolInfo, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
SchoolInfo originalSchoolInfo = schoolInfoService.getById(schoolInfo.getSchoolId());
if (originalSchoolInfo == null) {
//NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = schoolInfoService.verifyRelatedData(schoolInfo, originalSchoolInfo);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
if (!schoolInfoService.update(schoolInfo, originalSchoolInfo)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除校区数据数据。
*
* @param schoolId 删除对象主键Id。
* @return 应答结果对象。
*/
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long schoolId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(schoolId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
SchoolInfo originalSchoolInfo = schoolInfoService.getById(schoolId);
if (originalSchoolInfo == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!schoolInfoService.remove(schoolId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的校区数据列表。
*
* @param schoolInfoFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<SchoolInfo>> list(
@MyRequestBody SchoolInfo schoolInfoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, SchoolInfo.class);
List<SchoolInfo> resultList = schoolInfoService.getSchoolInfoListWithRelation(schoolInfoFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定校区数据对象详情。
*
* @param schoolId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<SchoolInfo> view(@RequestParam Long schoolId) {
if (MyCommonUtil.existBlankArgument(schoolId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
SchoolInfo schoolInfo = schoolInfoService.getByIdWithRelation(schoolId, MyRelationParam.full());
if (schoolInfo == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(schoolInfo);
}
/**
* 以字典形式返回全部校区数据数据集合。字典的键值为[schoolId, schoolName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDictSchoolInfo")
public ResponseResult<List<Map<String, Object>>> listDictSchoolInfo(SchoolInfo filter) {
List<SchoolInfo> resultList = schoolInfoService.getListByFilter(filter, null);
return ResponseResult.success(BeanQuery.select(
"schoolId as id", "schoolName as name").executeFrom(resultList));
}
}

View File

@@ -0,0 +1,100 @@
package com.orange.demo.app.controller;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 学生行为统计操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "学生行为统计管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/studentActionStats")
public class StudentActionStatsController {
@Autowired
private StudentActionStatsService studentActionStatsService;
/**
* 列出符合过滤条件的学生行为统计列表。
*
* @param studentActionStatsFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<StudentActionStats>> list(
@MyRequestBody StudentActionStats studentActionStatsFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionStats.class);
List<StudentActionStats> resultList = studentActionStatsService.getStudentActionStatsListWithRelation(studentActionStatsFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 分组列出符合过滤条件的学生行为统计列表。
*
* @param studentActionStatsFilter 过滤对象。
* @param groupParam 分组参数。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/listWithGroup")
public ResponseResult<MyPageData<StudentActionStats>> listWithGroup(
@MyRequestBody StudentActionStats studentActionStatsFilter,
@MyRequestBody MyGroupParam groupParam,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionStats.class);
groupParam = MyGroupParam.buildGroupBy(groupParam, StudentActionStats.class);
if (groupParam == null) {
return ResponseResult.error(
ErrorCodeEnum.INVALID_ARGUMENT_FORMAT, "数据参数错误,分组参数不能为空!");
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
MyGroupCriteria criteria = groupParam.getGroupCriteria();
List<StudentActionStats> resultList = studentActionStatsService.getGroupedStudentActionStatsListWithRelation(
studentActionStatsFilter, criteria.getGroupSelect(), criteria.getGroupBy(), orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定学生行为统计对象详情。
*
* @param statsId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<StudentActionStats> view(@RequestParam Long statsId) {
if (MyCommonUtil.existBlankArgument(statsId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
StudentActionStats studentActionStats = studentActionStatsService.getByIdWithRelation(statsId, MyRelationParam.full());
if (studentActionStats == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(studentActionStats);
}
}

View File

@@ -0,0 +1,159 @@
package com.orange.demo.app.controller;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import javax.validation.groups.Default;
/**
* 学生行为流水操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "学生行为流水管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/studentActionTrans")
public class StudentActionTransController {
@Autowired
private StudentActionTransService studentActionTransService;
/**
* 新增学生行为流水数据。
*
* @param studentActionTrans 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {
"studentActionTrans.transId",
"studentActionTrans.createTimeStart",
"studentActionTrans.createTimeEnd"})
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody StudentActionTrans studentActionTrans) {
String errorMessage = MyCommonUtil.getModelValidationError(studentActionTrans);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = studentActionTransService.verifyRelatedData(studentActionTrans, null);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
studentActionTrans = studentActionTransService.saveNew(studentActionTrans);
return ResponseResult.success(studentActionTrans.getTransId());
}
/**
* 更新学生行为流水数据。
*
* @param studentActionTrans 更新对象。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {
"studentActionTrans.createTimeStart",
"studentActionTrans.createTimeEnd"})
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody StudentActionTrans studentActionTrans) {
String errorMessage = MyCommonUtil.getModelValidationError(studentActionTrans, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
StudentActionTrans originalStudentActionTrans = studentActionTransService.getById(studentActionTrans.getTransId());
if (originalStudentActionTrans == null) {
//NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = studentActionTransService.verifyRelatedData(studentActionTrans, originalStudentActionTrans);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
if (!studentActionTransService.update(studentActionTrans, originalStudentActionTrans)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除学生行为流水数据。
*
* @param transId 删除对象主键Id。
* @return 应答结果对象。
*/
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long transId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(transId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
StudentActionTrans originalStudentActionTrans = studentActionTransService.getById(transId);
if (originalStudentActionTrans == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!studentActionTransService.remove(transId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的学生行为流水列表。
*
* @param studentActionTransFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<StudentActionTrans>> list(
@MyRequestBody StudentActionTrans studentActionTransFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentActionTrans.class);
List<StudentActionTrans> resultList = studentActionTransService.getStudentActionTransListWithRelation(studentActionTransFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定学生行为流水对象详情。
*
* @param transId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<StudentActionTrans> view(@RequestParam Long transId) {
if (MyCommonUtil.existBlankArgument(transId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
StudentActionTrans studentActionTrans = studentActionTransService.getByIdWithRelation(transId, MyRelationParam.full());
if (studentActionTrans == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(studentActionTrans);
}
}

View File

@@ -0,0 +1,426 @@
package com.orange.demo.app.controller;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import javax.validation.groups.Default;
import java.util.stream.Collectors;
/**
* 班级数据操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "班级数据管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/studentClass")
public class StudentClassController {
@Autowired
private StudentClassService studentClassService;
@Autowired
private CourseService courseService;
@Autowired
private StudentService studentService;
/**
* 新增班级数据数据。
*
* @param studentClass 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"studentClass.userId"})
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody StudentClass studentClass) {
String errorMessage = MyCommonUtil.getModelValidationError(studentClass);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = studentClassService.verifyRelatedData(studentClass, null);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
studentClass = studentClassService.saveNew(studentClass);
return ResponseResult.success(studentClass.getClassId());
}
/**
* 更新班级数据数据。
*
* @param studentClass 更新对象。
* @return 应答结果对象。
*/
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody StudentClass studentClass) {
String errorMessage = MyCommonUtil.getModelValidationError(studentClass, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
StudentClass originalStudentClass = studentClassService.getById(studentClass.getClassId());
if (originalStudentClass == null) {
//NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = studentClassService.verifyRelatedData(studentClass, originalStudentClass);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
if (!studentClassService.update(studentClass, originalStudentClass)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除班级数据数据。
*
* @param classId 删除对象主键Id。
* @return 应答结果对象。
*/
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long classId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(classId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
StudentClass originalStudentClass = studentClassService.getById(classId);
if (originalStudentClass == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!studentClassService.remove(classId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的班级数据列表。
*
* @param studentClassFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<StudentClass>> list(
@MyRequestBody StudentClass studentClassFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, StudentClass.class);
List<StudentClass> resultList = studentClassService.getStudentClassListWithRelation(studentClassFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定班级数据对象详情。
*
* @param classId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<StudentClass> view(@RequestParam Long classId) {
if (MyCommonUtil.existBlankArgument(classId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
StudentClass studentClass = studentClassService.getByIdWithRelation(classId, MyRelationParam.full());
if (studentClass == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(studentClass);
}
/**
* 列出不与指定班级数据存在多对多关系的 [课程数据] 列表数据。通常用于查看添加新 [课程数据] 对象的候选列表。
*
* @param classId 主表关联字段。
* @param courseFilter [课程数据] 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,返回符合条件的数据列表。
*/
@PostMapping("/listNotInClassCourse")
public ResponseResult<MyPageData<Course>> listNotInClassCourse(
@MyRequestBody Long classId,
@MyRequestBody Course courseFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doClassCourseVerify(classId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class);
List<Course> resultList =
courseService.getNotInCourseListByClassId(classId, courseFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 列出与指定班级数据存在多对多关系的 [课程数据] 列表数据。
*
* @param classId 主表关联字段。
* @param courseFilter [课程数据] 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,返回符合条件的数据列表。
*/
@PostMapping("/listClassCourse")
public ResponseResult<MyPageData<Course>> listClassCourse(
@MyRequestBody Long classId,
@MyRequestBody Course courseFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doClassCourseVerify(classId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, Course.class);
List<Course> resultList =
courseService.getCourseListByClassId(classId, courseFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
private ResponseResult<Void> doClassCourseVerify(Long classId) {
if (MyCommonUtil.existBlankArgument(classId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!studentClassService.existId(classId)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
return ResponseResult.success();
}
/**
* 批量添加班级数据和 [课程数据] 对象的多对多关联关系数据。
*
* @param classId 主表主键Id。
* @param classCourseList 关联对象列表。
* @return 应答结果对象。
*/
@PostMapping("/addClassCourse")
public ResponseResult<Void> addClassCourse(
@MyRequestBody Long classId,
@MyRequestBody(elementType = ClassCourse.class) List<ClassCourse> classCourseList) {
if (MyCommonUtil.existBlankArgument(classId, classCourseList)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
for (ClassCourse classCourse : classCourseList) {
String errorMessage = MyCommonUtil.getModelValidationError(classCourse);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
}
Set<Long> courseIdSet =
classCourseList.stream().map(ClassCourse::getCourseId).collect(Collectors.toSet());
if (!studentClassService.existId(classId)
|| !courseService.existUniqueKeyList("courseId", courseIdSet)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
studentClassService.addClassCourseList(classCourseList, classId);
return ResponseResult.success();
}
/**
* 更新指定班级数据和指定 [课程数据] 的多对多关联数据。
*
* @param classCourse 对多对中间表对象。
* @return 应答结果对象。
*/
@PostMapping("/updateClassCourse")
public ResponseResult<Void> updateClassCourse(@MyRequestBody ClassCourse classCourse) {
String errorMessage = MyCommonUtil.getModelValidationError(classCourse);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
if (!studentClassService.updateClassCourse(classCourse)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 显示班级数据和指定 [课程数据] 的多对多关联详情数据。
*
* @param classId 主表主键Id。
* @param courseId 从表主键Id。
* @return 应答结果对象,包括中间表详情。
*/
@GetMapping("/viewClassCourse")
public ResponseResult<ClassCourse> viewClassCourse(
@RequestParam Long classId, @RequestParam Long courseId) {
if (MyCommonUtil.existBlankArgument(classId, courseId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
ClassCourse classCourse = studentClassService.getClassCourse(classId, courseId);
if (classCourse == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(classCourse);
}
/**
* 移除指定班级数据和指定 [课程数据] 的多对多关联关系。
*
* @param classId 主表主键Id。
* @param courseId 从表主键Id。
* @return 应答结果对象。
*/
@PostMapping("/deleteClassCourse")
public ResponseResult<Void> deleteClassCourse(
@MyRequestBody Long classId, @MyRequestBody Long courseId) {
if (MyCommonUtil.existBlankArgument(classId, courseId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!studentClassService.removeClassCourse(classId, courseId)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 列出不与指定班级数据存在多对多关系的 [学生数据] 列表数据。通常用于查看添加新 [学生数据] 对象的候选列表。
*
* @param classId 主表关联字段。
* @param studentFilter [学生数据] 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,返回符合条件的数据列表。
*/
@PostMapping("/listNotInClassStudent")
public ResponseResult<MyPageData<Student>> listNotInClassStudent(
@MyRequestBody Long classId,
@MyRequestBody Student studentFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doClassStudentVerify(classId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class);
List<Student> resultList =
studentService.getNotInStudentListByClassId(classId, studentFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 列出与指定班级数据存在多对多关系的 [学生数据] 列表数据。
*
* @param classId 主表关联字段。
* @param studentFilter [学生数据] 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,返回符合条件的数据列表。
*/
@PostMapping("/listClassStudent")
public ResponseResult<MyPageData<Student>> listClassStudent(
@MyRequestBody Long classId,
@MyRequestBody Student studentFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
ResponseResult<Void> verifyResult = this.doClassStudentVerify(classId);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class);
List<Student> resultList =
studentService.getStudentListByClassId(classId, studentFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
private ResponseResult<Void> doClassStudentVerify(Long classId) {
if (MyCommonUtil.existBlankArgument(classId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!studentClassService.existId(classId)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
return ResponseResult.success();
}
/**
* 批量添加班级数据和 [学生数据] 对象的多对多关联关系数据。
*
* @param classId 主表主键Id。
* @param classStudentList 关联对象列表。
* @return 应答结果对象。
*/
@PostMapping("/addClassStudent")
public ResponseResult<Void> addClassStudent(
@MyRequestBody Long classId,
@MyRequestBody(elementType = ClassStudent.class) List<ClassStudent> classStudentList) {
if (MyCommonUtil.existBlankArgument(classId, classStudentList)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
for (ClassStudent classStudent : classStudentList) {
String errorMessage = MyCommonUtil.getModelValidationError(classStudent);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
}
Set<Long> studentIdSet =
classStudentList.stream().map(ClassStudent::getStudentId).collect(Collectors.toSet());
if (!studentClassService.existId(classId)
|| !studentService.existUniqueKeyList("studentId", studentIdSet)) {
return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID);
}
studentClassService.addClassStudentList(classStudentList, classId);
return ResponseResult.success();
}
/**
* 移除指定班级数据和指定 [学生数据] 的多对多关联关系。
*
* @param classId 主表主键Id。
* @param studentId 从表主键Id。
* @return 应答结果对象。
*/
@PostMapping("/deleteClassStudent")
public ResponseResult<Void> deleteClassStudent(
@MyRequestBody Long classId, @MyRequestBody Long studentId) {
if (MyCommonUtil.existBlankArgument(classId, studentId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!studentClassService.removeClassStudent(classId, studentId)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
}

View File

@@ -0,0 +1,180 @@
package com.orange.demo.app.controller;
import cn.jimmyshi.beanquery.BeanQuery;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.app.model.*;
import com.orange.demo.app.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import javax.validation.groups.Default;
/**
* 学生数据操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "学生数据管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/student")
public class StudentController {
@Autowired
private StudentService studentService;
/**
* 新增学生数据数据。
*
* @param student 新增对象。
* @return 应答结果对象包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {
"student.studentId",
"student.searchString",
"student.birthdayStart",
"student.birthdayEnd",
"student.registerTimeStart",
"student.registerTimeEnd"})
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody Student student) {
String errorMessage = MyCommonUtil.getModelValidationError(student);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = studentService.verifyRelatedData(student, null);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
student = studentService.saveNew(student);
return ResponseResult.success(student.getStudentId());
}
/**
* 更新学生数据数据。
*
* @param student 更新对象。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {
"student.searchString",
"student.birthdayStart",
"student.birthdayEnd",
"student.registerTimeStart",
"student.registerTimeEnd"})
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody Student student) {
String errorMessage = MyCommonUtil.getModelValidationError(student, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
// 验证关联Id的数据合法性
Student originalStudent = studentService.getById(student.getStudentId());
if (originalStudent == null) {
//NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
// 验证关联Id的数据合法性
CallResult callResult = studentService.verifyRelatedData(student, originalStudent);
if (!callResult.isSuccess()) {
errorMessage = callResult.getErrorMessage();
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
if (!studentService.update(student, originalStudent)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除学生数据数据。
*
* @param studentId 删除对象主键Id。
* @return 应答结果对象。
*/
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long studentId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(studentId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
Student originalStudent = studentService.getById(studentId);
if (originalStudent == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!studentService.remove(studentId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的学生数据列表。
*
* @param studentFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<Student>> list(
@MyRequestBody Student studentFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, Student.class);
List<Student> resultList = studentService.getStudentListWithRelation(studentFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定学生数据对象详情。
*
* @param studentId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<Student> view(@RequestParam Long studentId) {
if (MyCommonUtil.existBlankArgument(studentId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
Student student = studentService.getByIdWithRelation(studentId, MyRelationParam.full());
if (student == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(student);
}
/**
* 以字典形式返回全部学生数据数据集合。字典的键值为[studentId, studentName]。
* 白名单接口,登录用户均可访问。
*
* @param filter 过滤对象。
* @return 应答结果对象,包含的数据为 List<Map<String, String>>map中包含两条记录key的值分别是id和namevalue对应具体数据。
*/
@GetMapping("/listDictStudent")
public ResponseResult<List<Map<String, Object>>> listDictStudent(Student filter) {
List<Student> resultList = studentService.getListByFilter(filter, null);
return ResponseResult.success(BeanQuery.select(
"studentId as id", "studentName as name").executeFrom(resultList));
}
}

View File

@@ -0,0 +1,13 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.AreaCode;
/**
* 行政区划数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface AreaCodeMapper extends BaseDaoMapper<AreaCode> {
}

View File

@@ -0,0 +1,13 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.ClassCourse;
/**
* 数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface ClassCourseMapper extends BaseDaoMapper<ClassCourse> {
}

View File

@@ -0,0 +1,13 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.ClassStudent;
/**
* 数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface ClassStudentMapper extends BaseDaoMapper<ClassStudent> {
}

View File

@@ -0,0 +1,52 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.Course;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 课程数据数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface CourseMapper extends BaseDaoMapper<Course> {
/**
* 获取过滤后的对象列表。
*
* @param courseFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<Course> getCourseList(
@Param("courseFilter") Course courseFilter, @Param("orderBy") String orderBy);
/**
* 根据关联主表Id获取关联从表数据列表。
*
* @param classId 关联主表Id。
* @param courseFilter 从表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 从表数据列表。
*/
List<Course> getCourseListByClassId(
@Param("classId") Long classId,
@Param("courseFilter") Course courseFilter,
@Param("orderBy") String orderBy);
/**
* 根据关联主表Id获取关联从表中没有和主表建立关联关系的数据列表。
*
* @param classId 关联主表Id。
* @param courseFilter 过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 与主表没有建立关联的从表数据列表。
*/
List<Course> getNotInCourseListByClassId(
@Param("classId") Long classId,
@Param("courseFilter") Course courseFilter,
@Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,41 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.CourseTransStats;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 课程统计数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface CourseTransStatsMapper extends BaseDaoMapper<CourseTransStats> {
/**
* 获取分组计算后的数据对象列表。
*
* @param courseTransStatsFilter 主表过滤对象。
* @param groupSelect 分组显示字段列表字符串SELECT从句的参数。
* @param groupBy 分组字段列表字符串GROUP BY从句的参数。
* @param orderBy 排序字符串ORDER BY从句的参数。
* @return 对象列表。
*/
List<CourseTransStats> getGroupedCourseTransStatsList(
@Param("courseTransStatsFilter") CourseTransStats courseTransStatsFilter,
@Param("groupSelect") String groupSelect,
@Param("groupBy") String groupBy,
@Param("orderBy") String orderBy);
/**
* 获取过滤后的对象列表。
*
* @param courseTransStatsFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<CourseTransStats> getCourseTransStatsList(
@Param("courseTransStatsFilter") CourseTransStats courseTransStatsFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,13 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.Grade;
/**
* 年级数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface GradeMapper extends BaseDaoMapper<Grade> {
}

View File

@@ -0,0 +1,13 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.MaterialEdition;
/**
* 数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface MaterialEditionMapper extends BaseDaoMapper<MaterialEdition> {
}

View File

@@ -0,0 +1,26 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.SchoolInfo;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 校区数据数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface SchoolInfoMapper extends BaseDaoMapper<SchoolInfo> {
/**
* 获取过滤后的对象列表。
*
* @param schoolInfoFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<SchoolInfo> getSchoolInfoList(
@Param("schoolInfoFilter") SchoolInfo schoolInfoFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,41 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.StudentActionStats;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 学生行为统计数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface StudentActionStatsMapper extends BaseDaoMapper<StudentActionStats> {
/**
* 获取分组计算后的数据对象列表。
*
* @param studentActionStatsFilter 主表过滤对象。
* @param groupSelect 分组显示字段列表字符串SELECT从句的参数。
* @param groupBy 分组字段列表字符串GROUP BY从句的参数。
* @param orderBy 排序字符串ORDER BY从句的参数。
* @return 对象列表。
*/
List<StudentActionStats> getGroupedStudentActionStatsList(
@Param("studentActionStatsFilter") StudentActionStats studentActionStatsFilter,
@Param("groupSelect") String groupSelect,
@Param("groupBy") String groupBy,
@Param("orderBy") String orderBy);
/**
* 获取过滤后的对象列表。
*
* @param studentActionStatsFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<StudentActionStats> getStudentActionStatsList(
@Param("studentActionStatsFilter") StudentActionStats studentActionStatsFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,26 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.StudentActionTrans;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 学生行为流水数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface StudentActionTransMapper extends BaseDaoMapper<StudentActionTrans> {
/**
* 获取过滤后的对象列表。
*
* @param studentActionTransFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<StudentActionTrans> getStudentActionTransList(
@Param("studentActionTransFilter") StudentActionTrans studentActionTransFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,26 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.StudentClass;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 班级数据数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface StudentClassMapper extends BaseDaoMapper<StudentClass> {
/**
* 获取过滤后的对象列表。
*
* @param studentClassFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<StudentClass> getStudentClassList(
@Param("studentClassFilter") StudentClass studentClassFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,52 @@
package com.orange.demo.app.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.app.model.Student;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 学生数据数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface StudentMapper extends BaseDaoMapper<Student> {
/**
* 获取过滤后的对象列表。
*
* @param studentFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<Student> getStudentList(
@Param("studentFilter") Student studentFilter, @Param("orderBy") String orderBy);
/**
* 根据关联主表Id获取关联从表数据列表。
*
* @param classId 关联主表Id。
* @param studentFilter 从表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 从表数据列表。
*/
List<Student> getStudentListByClassId(
@Param("classId") Long classId,
@Param("studentFilter") Student studentFilter,
@Param("orderBy") String orderBy);
/**
* 根据关联主表Id获取关联从表中没有和主表建立关联关系的数据列表。
*
* @param classId 关联主表Id。
* @param studentFilter 过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 与主表没有建立关联的从表数据列表。
*/
List<Student> getNotInStudentListByClassId(
@Param("classId") Long classId,
@Param("studentFilter") Student studentFilter,
@Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,10 @@
<?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.orange.demo.app.dao.AreaCodeMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.AreaCode">
<id column="area_id" jdbcType="BIGINT" property="areaId"/>
<result column="area_name" jdbcType="VARCHAR" property="areaName"/>
<result column="area_level" jdbcType="INTEGER" property="areaLevel"/>
<result column="parent_id" jdbcType="BIGINT" property="parentId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,9 @@
<?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.orange.demo.app.dao.ClassCourseMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.ClassCourse">
<id column="class_id" jdbcType="BIGINT" property="classId"/>
<id column="course_id" jdbcType="BIGINT" property="courseId"/>
<result column="course_order" jdbcType="TINYINT" property="courseOrder"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,8 @@
<?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.orange.demo.app.dao.ClassStudentMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.ClassStudent">
<id column="class_id" jdbcType="BIGINT" property="classId"/>
<id column="student_id" jdbcType="BIGINT" property="studentId"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,101 @@
<?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.orange.demo.app.dao.CourseMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.Course">
<id column="course_id" jdbcType="BIGINT" property="courseId"/>
<result column="course_name" jdbcType="VARCHAR" property="courseName"/>
<result column="price" jdbcType="DECIMAL" property="price"/>
<result column="description" jdbcType="VARCHAR" property="description"/>
<result column="difficulty" jdbcType="INTEGER" property="difficulty"/>
<result column="grade_id" jdbcType="TINYINT" property="gradeId"/>
<result column="subject_id" jdbcType="TINYINT" property="subjectId"/>
<result column="class_hour" jdbcType="INTEGER" property="classHour"/>
<result column="picture_url" jdbcType="VARCHAR" property="pictureUrl"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<resultMap id="BaseResultMapWithClassCourse" type="com.orange.demo.app.model.Course" extends="BaseResultMap">
<association property="classCourse" column="course_id" foreignColumn="course_id"
notNullColumn="course_id" resultMap="com.orange.demo.app.dao.ClassCourseMapper.BaseResultMap" />
</resultMap>
<sql id="filterRef">
<if test="courseFilter != null">
<if test="courseFilter.courseName != null and courseFilter.courseName != ''">
<bind name = "safeCourseName" value = "'%' + courseFilter.courseName + '%'" />
AND zz_course.course_name LIKE #{safeCourseName}
</if>
<if test="courseFilter.priceStart != null">
AND zz_course.price &gt;= #{courseFilter.priceStart}
</if>
<if test="courseFilter.priceEnd != null">
AND zz_course.price &lt;= #{courseFilter.priceEnd}
</if>
<if test="courseFilter.difficulty != null">
AND zz_course.difficulty = #{courseFilter.difficulty}
</if>
<if test="courseFilter.gradeId != null">
AND zz_course.grade_id = #{courseFilter.gradeId}
</if>
<if test="courseFilter.subjectId != null">
AND zz_course.subject_id = #{courseFilter.subjectId}
</if>
<if test="courseFilter.classHourStart != null">
AND zz_course.class_hour &gt;= #{courseFilter.classHourStart}
</if>
<if test="courseFilter.classHourEnd != null">
AND zz_course.class_hour &lt;= #{courseFilter.classHourEnd}
</if>
<if test="courseFilter.createTimeStart != null and courseFilter.createTimeStart != ''">
AND zz_course.create_time &gt;= #{courseFilter.createTimeStart}
</if>
<if test="courseFilter.createTimeEnd != null and courseFilter.createTimeEnd != ''">
AND zz_course.create_time &lt;= #{courseFilter.createTimeEnd}
</if>
</if>
</sql>
<select id="getCourseList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.Course">
SELECT * FROM zz_course
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getCourseListByClassId" resultMap="BaseResultMapWithClassCourse">
SELECT
zz_course.*,
zz_class_course.*
FROM
zz_course,
zz_class_course
<where>
AND zz_class_course.class_id = #{classId}
AND zz_class_course.course_id = zz_course.course_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getNotInCourseListByClassId" resultMap="BaseResultMap">
SELECT
zz_course.*
FROM
zz_course
<where>
AND NOT EXISTS (SELECT * FROM zz_class_course
WHERE zz_class_course.class_id = #{classId} AND zz_class_course.course_id = zz_course.course_id)
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,60 @@
<?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.orange.demo.app.dao.CourseTransStatsMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.CourseTransStats">
<id column="stats_id" jdbcType="BIGINT" property="statsId"/>
<result column="stats_date" jdbcType="DATE" property="statsDate"/>
<result column="subject_id" jdbcType="TINYINT" property="subjectId"/>
<result column="grade_id" jdbcType="TINYINT" property="gradeId"/>
<result column="grade_name" jdbcType="VARCHAR" property="gradeName"/>
<result column="course_id" jdbcType="BIGINT" property="courseId"/>
<result column="course_name" jdbcType="VARCHAR" property="courseName"/>
<result column="student_attend_count" jdbcType="INTEGER" property="studentAttendCount"/>
<result column="student_flower_amount" jdbcType="INTEGER" property="studentFlowerAmount"/>
<result column="student_flower_count" jdbcType="INTEGER" property="studentFlowerCount"/>
</resultMap>
<sql id="filterRef">
<if test="courseTransStatsFilter != null">
<if test="courseTransStatsFilter.statsDateStart != null and courseTransStatsFilter.statsDateStart != ''">
AND zz_course_trans_stats.stats_date &gt;= #{courseTransStatsFilter.statsDateStart}
</if>
<if test="courseTransStatsFilter.statsDateEnd != null and courseTransStatsFilter.statsDateEnd != ''">
AND zz_course_trans_stats.stats_date &lt;= #{courseTransStatsFilter.statsDateEnd}
</if>
<if test="courseTransStatsFilter.subjectId != null">
AND zz_course_trans_stats.subject_id = #{courseTransStatsFilter.subjectId}
</if>
<if test="courseTransStatsFilter.gradeId != null">
AND zz_course_trans_stats.grade_id = #{courseTransStatsFilter.gradeId}
</if>
</if>
</sql>
<select id="getGroupedCourseTransStatsList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.CourseTransStats">
SELECT * FROM
(SELECT
SUM(student_attend_count) student_attend_count,
SUM(student_flower_amount) student_flower_amount,
SUM(student_flower_count) student_flower_count,
${groupSelect}
FROM zz_course_trans_stats
<where>
<include refid="filterRef"/>
</where>
GROUP BY ${groupBy}) zz_course_trans_stats
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getCourseTransStatsList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.CourseTransStats">
SELECT * FROM zz_course_trans_stats
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,9 @@
<?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.orange.demo.app.dao.GradeMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.Grade">
<id column="grade_id" jdbcType="INTEGER" property="gradeId"/>
<result column="grade_name" jdbcType="VARCHAR" property="gradeName"/>
<result column="status" jdbcType="INTEGER" property="status"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,9 @@
<?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.orange.demo.app.dao.MaterialEditionMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.MaterialEdition">
<id column="edition_id" jdbcType="INTEGER" property="editionId"/>
<result column="edition_name" jdbcType="VARCHAR" property="editionName"/>
<result column="status" jdbcType="INTEGER" property="status"/>
</resultMap>
</mapper>

View File

@@ -0,0 +1,35 @@
<?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.orange.demo.app.dao.SchoolInfoMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.SchoolInfo">
<id column="school_id" jdbcType="BIGINT" property="schoolId"/>
<result column="school_name" jdbcType="VARCHAR" property="schoolName"/>
<result column="province_id" jdbcType="BIGINT" property="provinceId"/>
<result column="city_id" jdbcType="BIGINT" property="cityId"/>
</resultMap>
<sql id="filterRef">
<if test="schoolInfoFilter != null">
<if test="schoolInfoFilter.schoolName != null and schoolInfoFilter.schoolName != ''">
<bind name = "safeSchoolName" value = "'%' + schoolInfoFilter.schoolName + '%'" />
AND zz_school_info.school_name LIKE #{safeSchoolName}
</if>
<if test="schoolInfoFilter.provinceId != null">
AND zz_school_info.province_id = #{schoolInfoFilter.provinceId}
</if>
<if test="schoolInfoFilter.cityId != null">
AND zz_school_info.city_id = #{schoolInfoFilter.cityId}
</if>
</if>
</sql>
<select id="getSchoolInfoList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.SchoolInfo">
SELECT * FROM zz_school_info
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,86 @@
<?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.orange.demo.app.dao.StudentActionStatsMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.StudentActionStats">
<id column="stats_id" jdbcType="BIGINT" property="statsId"/>
<result column="stats_date" jdbcType="DATE" property="statsDate"/>
<result column="stats_month" jdbcType="DATE" property="statsMonth"/>
<result column="grade_id" jdbcType="INTEGER" property="gradeId"/>
<result column="province_id" jdbcType="BIGINT" property="provinceId"/>
<result column="city_id" jdbcType="BIGINT" property="cityId"/>
<result column="buy_course_amount" jdbcType="INTEGER" property="buyCourseAmount"/>
<result column="buy_course_count" jdbcType="INTEGER" property="buyCourseCount"/>
<result column="buy_video_amount" jdbcType="INTEGER" property="buyVideoAmount"/>
<result column="buy_video_count" jdbcType="INTEGER" property="buyVideoCount"/>
<result column="buy_paper_amount" jdbcType="INTEGER" property="buyPaperAmount"/>
<result column="buy_paper_count" jdbcType="INTEGER" property="buyPaperCount"/>
<result column="buy_flower_amount" jdbcType="INTEGER" property="buyFlowerAmount"/>
<result column="buy_flower_count" jdbcType="INTEGER" property="buyFlowerCount"/>
<result column="recharge_coin_amount" jdbcType="INTEGER" property="rechargeCoinAmount"/>
<result column="recharge_coin_count" jdbcType="INTEGER" property="rechargeCoinCount"/>
<result column="do_course_count" jdbcType="INTEGER" property="doCourseCount"/>
<result column="watch_video_count" jdbcType="INTEGER" property="watchVideoCount"/>
<result column="watch_video_total_second" jdbcType="INTEGER" property="watchVideoTotalSecond"/>
<result column="do_exercise_count" jdbcType="INTEGER" property="doExerciseCount"/>
<result column="do_exercise_correct_count" jdbcType="INTEGER" property="doExerciseCorrectCount"/>
</resultMap>
<sql id="filterRef">
<if test="studentActionStatsFilter != null">
<if test="studentActionStatsFilter.statsDateStart != null and studentActionStatsFilter.statsDateStart != ''">
AND zz_student_action_stats.stats_date &gt;= #{studentActionStatsFilter.statsDateStart}
</if>
<if test="studentActionStatsFilter.statsDateEnd != null and studentActionStatsFilter.statsDateEnd != ''">
AND zz_student_action_stats.stats_date &lt;= #{studentActionStatsFilter.statsDateEnd}
</if>
<if test="studentActionStatsFilter.gradeId != null">
AND zz_student_action_stats.grade_id = #{studentActionStatsFilter.gradeId}
</if>
<if test="studentActionStatsFilter.provinceId != null">
AND zz_student_action_stats.province_id = #{studentActionStatsFilter.provinceId}
</if>
<if test="studentActionStatsFilter.cityId != null">
AND zz_student_action_stats.city_id = #{studentActionStatsFilter.cityId}
</if>
</if>
</sql>
<select id="getGroupedStudentActionStatsList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.StudentActionStats">
SELECT * FROM
(SELECT
SUM(buy_course_amount) buy_course_amount,
COUNT(buy_course_count) buy_course_count,
SUM(buy_video_amount) buy_video_amount,
COUNT(buy_video_count) buy_video_count,
SUM(buy_paper_amount) buy_paper_amount,
COUNT(buy_paper_count) buy_paper_count,
SUM(buy_flower_amount) buy_flower_amount,
COUNT(buy_flower_count) buy_flower_count,
SUM(recharge_coin_amount) recharge_coin_amount,
COUNT(recharge_coin_count) recharge_coin_count,
SUM(do_course_count) do_course_count,
SUM(watch_video_count) watch_video_count,
SUM(watch_video_total_second) watch_video_total_second,
SUM(do_exercise_count) do_exercise_count,
SUM(do_exercise_correct_count) do_exercise_correct_count,
${groupSelect}
FROM zz_student_action_stats
<where>
<include refid="filterRef"/>
</where>
GROUP BY ${groupBy}) zz_student_action_stats
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getStudentActionStatsList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.StudentActionStats">
SELECT * FROM zz_student_action_stats
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,57 @@
<?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.orange.demo.app.dao.StudentActionTransMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.StudentActionTrans">
<id column="trans_id" jdbcType="BIGINT" property="transId"/>
<result column="student_id" jdbcType="BIGINT" property="studentId"/>
<result column="student_name" jdbcType="VARCHAR" property="studentName"/>
<result column="school_id" jdbcType="BIGINT" property="schoolId"/>
<result column="grade_id" jdbcType="INTEGER" property="gradeId"/>
<result column="action_type" jdbcType="TINYINT" property="actionType"/>
<result column="device_type" jdbcType="TINYINT" property="deviceType"/>
<result column="watch_video_seconds" jdbcType="INTEGER" property="watchVideoSeconds"/>
<result column="flower_count" jdbcType="INTEGER" property="flowerCount"/>
<result column="paper_count" jdbcType="INTEGER" property="paperCount"/>
<result column="video_count" jdbcType="INTEGER" property="videoCount"/>
<result column="course_count" jdbcType="INTEGER" property="courseCount"/>
<result column="coin_count" jdbcType="INTEGER" property="coinCount"/>
<result column="exercise_correct_flag" jdbcType="TINYINT" property="exerciseCorrectFlag"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
</resultMap>
<sql id="filterRef">
<if test="studentActionTransFilter != null">
<if test="studentActionTransFilter.studentId != null">
AND zz_student_action_trans.student_id = #{studentActionTransFilter.studentId}
</if>
<if test="studentActionTransFilter.schoolId != null">
AND zz_student_action_trans.school_id = #{studentActionTransFilter.schoolId}
</if>
<if test="studentActionTransFilter.gradeId != null">
AND zz_student_action_trans.grade_id = #{studentActionTransFilter.gradeId}
</if>
<if test="studentActionTransFilter.actionType != null">
AND zz_student_action_trans.action_type = #{studentActionTransFilter.actionType}
</if>
<if test="studentActionTransFilter.deviceType != null">
AND zz_student_action_trans.device_type = #{studentActionTransFilter.deviceType}
</if>
<if test="studentActionTransFilter.createTimeStart != null and studentActionTransFilter.createTimeStart != ''">
AND zz_student_action_trans.create_time &gt;= #{studentActionTransFilter.createTimeStart}
</if>
<if test="studentActionTransFilter.createTimeEnd != null and studentActionTransFilter.createTimeEnd != ''">
AND zz_student_action_trans.create_time &lt;= #{studentActionTransFilter.createTimeEnd}
</if>
</if>
</sql>
<select id="getStudentActionTransList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.StudentActionTrans">
SELECT * FROM zz_student_action_trans
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,40 @@
<?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.orange.demo.app.dao.StudentClassMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.StudentClass">
<id column="class_id" jdbcType="BIGINT" property="classId"/>
<result column="class_name" jdbcType="VARCHAR" property="className"/>
<result column="school_id" jdbcType="BIGINT" property="schoolId"/>
<result column="leader_id" jdbcType="BIGINT" property="leaderId"/>
<result column="finish_class_hour" jdbcType="INTEGER" property="finishClassHour"/>
<result column="class_level" jdbcType="TINYINT" property="classLevel"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="status" jdbcType="TINYINT" property="status"/>
</resultMap>
<sql id="filterRef">
<if test="studentClassFilter != null">
<if test="studentClassFilter.className != null and studentClassFilter.className != ''">
AND zz_class.class_name = #{studentClassFilter.className}
</if>
<if test="studentClassFilter.schoolId != null">
AND zz_class.school_id = #{studentClassFilter.schoolId}
</if>
<if test="studentClassFilter.classLevel != null">
AND zz_class.class_level = #{studentClassFilter.classLevel}
</if>
</if>
AND zz_class.status = ${@com.orange.demo.common.core.constant.GlobalDeletedFlag@NORMAL}
</sql>
<select id="getStudentClassList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.StudentClass">
SELECT * FROM zz_class
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,101 @@
<?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.orange.demo.app.dao.StudentMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.app.model.Student">
<id column="student_id" jdbcType="BIGINT" property="studentId"/>
<result column="login_mobile" jdbcType="VARCHAR" property="loginMobile"/>
<result column="student_name" jdbcType="VARCHAR" property="studentName"/>
<result column="province_id" jdbcType="BIGINT" property="provinceId"/>
<result column="city_id" jdbcType="BIGINT" property="cityId"/>
<result column="district_id" jdbcType="BIGINT" property="districtId"/>
<result column="gender" jdbcType="INTEGER" property="gender"/>
<result column="birthday" jdbcType="DATE" property="birthday"/>
<result column="experience_level" jdbcType="TINYINT" property="experienceLevel"/>
<result column="total_coin" jdbcType="INTEGER" property="totalCoin"/>
<result column="left_coin" jdbcType="INTEGER" property="leftCoin"/>
<result column="grade_id" jdbcType="INTEGER" property="gradeId"/>
<result column="school_id" jdbcType="BIGINT" property="schoolId"/>
<result column="register_time" jdbcType="TIMESTAMP" property="registerTime"/>
<result column="status" jdbcType="TINYINT" property="status"/>
</resultMap>
<sql id="filterRef">
<if test="studentFilter != null">
<if test="studentFilter.provinceId != null">
AND zz_student.province_id = #{studentFilter.provinceId}
</if>
<if test="studentFilter.cityId != null">
AND zz_student.city_id = #{studentFilter.cityId}
</if>
<if test="studentFilter.districtId != null">
AND zz_student.district_id = #{studentFilter.districtId}
</if>
<if test="studentFilter.birthdayStart != null and studentFilter.birthdayStart != ''">
AND zz_student.birthday &gt;= #{studentFilter.birthdayStart}
</if>
<if test="studentFilter.birthdayEnd != null and studentFilter.birthdayEnd != ''">
AND zz_student.birthday &lt;= #{studentFilter.birthdayEnd}
</if>
<if test="studentFilter.gradeId != null">
AND zz_student.grade_id = #{studentFilter.gradeId}
</if>
<if test="studentFilter.schoolId != null">
AND zz_student.school_id = #{studentFilter.schoolId}
</if>
<if test="studentFilter.registerTimeStart != null and studentFilter.registerTimeStart != ''">
AND zz_student.register_time &gt;= #{studentFilter.registerTimeStart}
</if>
<if test="studentFilter.registerTimeEnd != null and studentFilter.registerTimeEnd != ''">
AND zz_student.register_time &lt;= #{studentFilter.registerTimeEnd}
</if>
<if test="studentFilter.status != null">
AND zz_student.status = #{studentFilter.status}
</if>
<if test="studentFilter.searchString != null and studentFilter.searchString != ''">
<bind name = "safeSearchString" value = "'%' + studentFilter.searchString + '%'" />
AND CONCAT(IFNULL(zz_student.login_mobile,''), IFNULL(zz_student.student_name,'')) LIKE #{safeSearchString}
</if>
</if>
</sql>
<select id="getStudentList" resultMap="BaseResultMap" parameterType="com.orange.demo.app.model.Student">
SELECT * FROM zz_student
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getStudentListByClassId" resultMap="BaseResultMap">
SELECT
zz_student.*
FROM
zz_student,
zz_class_student
<where>
AND zz_class_student.class_id = #{classId}
AND zz_class_student.student_id = zz_student.student_id
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<select id="getNotInStudentListByClassId" resultMap="BaseResultMap">
SELECT
zz_student.*
FROM
zz_student
<where>
AND NOT EXISTS (SELECT * FROM zz_class_student
WHERE zz_class_student.class_id = #{classId} AND zz_class_student.student_id = zz_student.student_id)
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,48 @@
package com.orange.demo.app.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
/**
* 行政区划实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("行政区划实体对象")
@Data
@Table(name = "zz_area_code")
public class AreaCode {
/**
* 行政区划主键Id
*/
@ApiModelProperty(value = "行政区划主键Id", required = true)
@Id
@Column(name = "area_id")
private Long areaId;
/**
* 行政区划名称
*/
@ApiModelProperty(value = "行政区划名称")
@Column(name = "area_name")
private String areaName;
/**
* 行政区划级别 (1: 省级别 2: 市级别 3: 区级别)
*/
@ApiModelProperty(value = "行政区划级别")
@Column(name = "area_level")
private Integer areaLevel;
/**
* 父级行政区划Id
*/
@ApiModelProperty(value = "父级行政区划Id")
@Column(name = "parent_id")
private Long parentId;
}

View File

@@ -0,0 +1,46 @@
package com.orange.demo.app.model;
import com.orange.demo.common.core.validator.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
/**
* ClassCourse实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("ClassCourse实体对象")
@Data
@Table(name = "zz_class_course")
public class ClassCourse {
/**
* 班级Id。
*/
@ApiModelProperty(value = "班级Id", required = true)
@NotNull(message = "数据验证失败班级Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "class_id")
private Long classId;
/**
* 课程Id。
*/
@ApiModelProperty(value = "课程Id", required = true)
@NotNull(message = "数据验证失败课程Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "course_id")
private Long courseId;
/**
* 课程顺序(数值越小越靠前)。
*/
@ApiModelProperty(value = "课程顺序(数值越小越靠前)", required = true)
@NotNull(message = "数据验证失败,课程顺序(数值越小越靠前)不能为空!", groups = {UpdateGroup.class})
@Column(name = "course_order")
private Integer courseOrder;
}

View File

@@ -0,0 +1,38 @@
package com.orange.demo.app.model;
import com.orange.demo.common.core.validator.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
/**
* ClassStudent实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("ClassStudent实体对象")
@Data
@Table(name = "zz_class_student")
public class ClassStudent {
/**
* 班级Id。
*/
@ApiModelProperty(value = "班级Id", required = true)
@NotNull(message = "数据验证失败班级Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "class_id")
private Long classId;
/**
* 学生Id。
*/
@ApiModelProperty(value = "学生Id", required = true)
@NotNull(message = "数据验证失败学生Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "student_id")
private Long studentId;
}

View File

@@ -0,0 +1,197 @@
package com.orange.demo.app.model;
import com.orange.demo.app.model.constant.CourseDifficult;
import com.orange.demo.application.common.constant.Subject;
import com.orange.demo.common.core.upload.UploadStoreTypeEnum;
import com.orange.demo.common.core.annotation.UploadFlagColumn;
import com.orange.demo.common.core.annotation.RelationDict;
import com.orange.demo.common.core.annotation.RelationConstDict;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.common.core.validator.ConstDictRef;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
/**
* Course实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("Course实体对象")
@Data
@Table(name = "zz_course")
public class Course {
/**
* 主键Id。
*/
@ApiModelProperty(value = "主键Id", required = true)
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "course_id")
private Long courseId;
/**
* 课程名称。
*/
@ApiModelProperty(value = "课程名称", required = true)
@NotBlank(message = "数据验证失败,课程名称不能为空!")
@Column(name = "course_name")
private String courseName;
/**
* 课程价格。
*/
@ApiModelProperty(value = "课程价格", required = true)
@NotNull(message = "数据验证失败,课程价格不能为空!")
private BigDecimal price;
/**
* 课程描述。
*/
@ApiModelProperty(value = "课程描述")
private String description;
/**
* 课程难度(0: 容易 1: 普通 2: 很难)。
*/
@ApiModelProperty(value = "课程难度(0: 容易 1: 普通 2: 很难)", required = true)
@NotNull(message = "数据验证失败,课程难度不能为空!")
@ConstDictRef(constDictClass = CourseDifficult.class, message = "数据验证失败,课程难度为无效值!")
private Integer difficulty;
/**
* 年级Id。
*/
@ApiModelProperty(value = "年级Id", required = true)
@NotNull(message = "数据验证失败,所属年级不能为空!")
@Column(name = "grade_id")
private Integer gradeId;
/**
* 学科Id。
*/
@ApiModelProperty(value = "学科Id", required = true)
@NotNull(message = "数据验证失败,所属学科不能为空!")
@ConstDictRef(constDictClass = Subject.class, message = "数据验证失败,所属学科为无效值!")
@Column(name = "subject_id")
private Integer subjectId;
/**
* 课时数量。
*/
@ApiModelProperty(value = "课时数量", required = true)
@NotNull(message = "数据验证失败,课时数量不能为空!")
@Column(name = "class_hour")
private Integer classHour;
/**
* 多张课程图片地址。
*/
@ApiModelProperty(value = "多张课程图片地址", required = true)
@UploadFlagColumn(storeType = UploadStoreTypeEnum.LOCAL_SYSTEM)
@NotBlank(message = "数据验证失败,课程图片不能为空!")
@Column(name = "picture_url")
private String pictureUrl;
/**
* 创建用户Id。
*/
@ApiModelProperty(value = "创建用户Id")
@Column(name = "create_user_id")
private Long createUserId;
/**
* 创建时间。
*/
@ApiModelProperty(value = "创建时间")
@Column(name = "create_time")
private Date createTime;
/**
* 最后修改时间。
*/
@ApiModelProperty(value = "最后修改时间")
@Column(name = "update_time")
private Date updateTime;
/**
* price 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "price 范围过滤起始值(>=)")
@Transient
private BigDecimal priceStart;
/**
* price 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "price 范围过滤结束值(<=)")
@Transient
private BigDecimal priceEnd;
/**
* classHour 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "classHour 范围过滤起始值(>=)")
@Transient
private Integer classHourStart;
/**
* classHour 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "classHour 范围过滤结束值(<=)")
@Transient
private Integer classHourEnd;
/**
* createTime 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "createTime 范围过滤起始值(>=)")
@Transient
private String createTimeStart;
/**
* createTime 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "createTime 范围过滤结束值(<=)")
@Transient
private String createTimeEnd;
/**
* courseId 的多对多关联表数据对象。
*/
@ApiModelProperty(hidden = true)
@Transient
private ClassCourse classCourse;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "gradeId",
slaveServiceName = "gradeService",
slaveModelClass = Grade.class,
slaveIdField = "gradeId",
slaveNameField = "gradeName")
@Transient
private Map<String, Object> gradeIdDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "difficulty",
constantDictClass = CourseDifficult.class)
@Transient
private Map<String, Object> difficultyDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "subjectId",
constantDictClass = Subject.class)
@Transient
private Map<String, Object> subjectIdDictMap;
}

View File

@@ -0,0 +1,139 @@
package com.orange.demo.app.model;
import com.orange.demo.application.common.constant.Subject;
import com.orange.demo.common.core.annotation.RelationDict;
import com.orange.demo.common.core.annotation.RelationConstDict;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.common.core.validator.ConstDictRef;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Map;
/**
* CourseTransStats实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("CourseTransStats实体对象")
@Data
@Table(name = "zz_course_trans_stats")
public class CourseTransStats {
/**
* 主键Id。
*/
@ApiModelProperty(value = "主键Id", required = true)
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "stats_id")
private Long statsId;
/**
* 统计日期。
*/
@ApiModelProperty(value = "统计日期", required = true)
@NotNull(message = "数据验证失败,统计日期不能为空!")
@Column(name = "stats_date")
private Date statsDate;
/**
* 科目Id。
*/
@ApiModelProperty(value = "科目Id", required = true)
@NotNull(message = "数据验证失败,所属科目不能为空!")
@ConstDictRef(constDictClass = Subject.class, message = "数据验证失败,所属科目为无效值!")
@Column(name = "subject_id")
private Integer subjectId;
/**
* 年级Id。
*/
@ApiModelProperty(value = "年级Id", required = true)
@NotNull(message = "数据验证失败,所属年级不能为空!")
@Column(name = "grade_id")
private Integer gradeId;
/**
* 年级名称。
*/
@ApiModelProperty(value = "年级名称")
@Column(name = "grade_name")
private String gradeName;
/**
* 课程Id。
*/
@ApiModelProperty(value = "课程Id", required = true)
@NotNull(message = "数据验证失败课程Id不能为空")
@Column(name = "course_id")
private Long courseId;
/**
* 课程名称。
*/
@ApiModelProperty(value = "课程名称")
@Column(name = "course_name")
private String courseName;
/**
* 学生上课次数。
*/
@ApiModelProperty(value = "学生上课次数", required = true)
@NotNull(message = "数据验证失败,上课次数不能为空!")
@Column(name = "student_attend_count")
private Integer studentAttendCount;
/**
* 学生献花数量。
*/
@ApiModelProperty(value = "学生献花数量", required = true)
@NotNull(message = "数据验证失败,献花数量不能为空!")
@Column(name = "student_flower_amount")
private Integer studentFlowerAmount;
/**
* 学生献花次数。
*/
@ApiModelProperty(value = "学生献花次数", required = true)
@NotNull(message = "数据验证失败,献花次数不能为空!")
@Column(name = "student_flower_count")
private Integer studentFlowerCount;
/**
* statsDate 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "statsDate 范围过滤起始值(>=)")
@Transient
private String statsDateStart;
/**
* statsDate 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "statsDate 范围过滤结束值(<=)")
@Transient
private String statsDateEnd;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "gradeId",
slaveServiceName = "gradeService",
slaveModelClass = Grade.class,
slaveIdField = "gradeId",
slaveNameField = "gradeName")
@Transient
private Map<String, Object> gradeIdDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "subjectId",
constantDictClass = Subject.class)
@Transient
private Map<String, Object> subjectIdDictMap;
}

View File

@@ -0,0 +1,48 @@
package com.orange.demo.app.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.orange.demo.common.core.annotation.DeletedFlagColumn;
import com.orange.demo.common.core.validator.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
/**
* Grade实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("Grade实体对象")
@Data
@Table(name = "zz_grade")
public class Grade {
/**
* 主键Id。
*/
@ApiModelProperty(value = "主键Id", required = true)
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "grade_id")
private Integer gradeId;
/**
* 年级名称。
*/
@ApiModelProperty(value = "年级名称", required = true)
@NotBlank(message = "数据验证失败,年级名称不能为空!")
@Column(name = "grade_name")
private String gradeName;
/**
* 逻辑删除标记字段(1: 正常 -1: 已删除)。
*/
@ApiModelProperty(hidden = true)
@JSONField(serialize = false)
@DeletedFlagColumn
private Integer status;
}

View File

@@ -0,0 +1,45 @@
package com.orange.demo.app.model;
import com.orange.demo.common.core.validator.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
/**
* MaterialEdition实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("MaterialEdition实体对象")
@Data
@Table(name = "zz_material_edition")
public class MaterialEdition {
/**
* 主键Id。
*/
@ApiModelProperty(value = "主键Id", required = true)
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "edition_id")
private Integer editionId;
/**
* 教材版本名称。
*/
@ApiModelProperty(value = "教材版本名称", required = true)
@NotBlank(message = "数据验证失败,教材版本名称不能为空!")
@Column(name = "edition_name")
private String editionName;
/**
* 是否正在使用0不是1
*/
@ApiModelProperty(value = "是否正在使用0不是1", required = true)
@NotNull(message = "数据验证失败是否正在使用0不是1不能为空")
private Integer status;
}

View File

@@ -0,0 +1,76 @@
package com.orange.demo.app.model;
import com.orange.demo.common.core.annotation.RelationDict;
import com.orange.demo.common.core.validator.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.util.Map;
/**
* SchoolInfo实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("SchoolInfo实体对象")
@Data
@Table(name = "zz_school_info")
public class SchoolInfo {
/**
* 学校Id。
*/
@ApiModelProperty(value = "学校Id", required = true)
@NotNull(message = "数据验证失败学校Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "school_id")
private Long schoolId;
/**
* 学校名称。
*/
@ApiModelProperty(value = "学校名称", required = true)
@NotBlank(message = "数据验证失败,学校名称不能为空!")
@Column(name = "school_name")
private String schoolName;
/**
* 所在省Id。
*/
@ApiModelProperty(value = "所在省Id", required = true)
@NotNull(message = "数据验证失败,所在省份不能为空!")
@Column(name = "province_id")
private Long provinceId;
/**
* 所在城市Id。
*/
@ApiModelProperty(value = "所在城市Id", required = true)
@NotNull(message = "数据验证失败,所在城市不能为空!")
@Column(name = "city_id")
private Long cityId;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "provinceId",
slaveServiceName = "areaCodeService",
slaveModelClass = AreaCode.class,
slaveIdField = "areaId",
slaveNameField = "areaName")
@Transient
private Map<String, Object> provinceIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "cityId",
slaveServiceName = "areaCodeService",
slaveModelClass = AreaCode.class,
slaveIdField = "areaId",
slaveNameField = "areaName")
@Transient
private Map<String, Object> cityIdDictMap;
}

View File

@@ -0,0 +1,255 @@
package com.orange.demo.app.model;
import com.orange.demo.application.common.constant.Gender;
import com.orange.demo.application.common.constant.ExpLevel;
import com.orange.demo.application.common.constant.StudentStatus;
import com.orange.demo.common.core.annotation.RelationDict;
import com.orange.demo.common.core.annotation.RelationConstDict;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.common.core.validator.ConstDictRef;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Map;
/**
* Student实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("Student实体对象")
@Data
@Table(name = "zz_student")
public class Student {
/**
* 学生Id。
*/
@ApiModelProperty(value = "学生Id", required = true)
@NotNull(message = "数据验证失败学生Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "student_id")
private Long studentId;
/**
* 登录手机。
*/
@ApiModelProperty(value = "登录手机", required = true)
@NotBlank(message = "数据验证失败,手机号码不能为空!")
@Column(name = "login_mobile")
private String loginMobile;
/**
* 学生姓名。
*/
@ApiModelProperty(value = "学生姓名", required = true)
@NotBlank(message = "数据验证失败,学生姓名不能为空!")
@Column(name = "student_name")
private String studentName;
/**
* 所在省份Id。
*/
@ApiModelProperty(value = "所在省份Id", required = true)
@NotNull(message = "数据验证失败,所在省份不能为空!")
@Column(name = "province_id")
private Long provinceId;
/**
* 所在城市Id。
*/
@ApiModelProperty(value = "所在城市Id", required = true)
@NotNull(message = "数据验证失败,所在城市不能为空!")
@Column(name = "city_id")
private Long cityId;
/**
* 区县Id。
*/
@ApiModelProperty(value = "区县Id", required = true)
@NotNull(message = "数据验证失败,所在区县不能为空!")
@Column(name = "district_id")
private Long districtId;
/**
* 学生性别 (0: 女生 1: 男生)。
*/
@ApiModelProperty(value = "学生性别 (0: 女生 1: 男生)", required = true)
@NotNull(message = "数据验证失败,学生性别不能为空!")
@ConstDictRef(constDictClass = Gender.class, message = "数据验证失败,学生性别为无效值!")
private Integer gender;
/**
* 生日。
*/
@ApiModelProperty(value = "生日", required = true)
@NotNull(message = "数据验证失败,出生日期不能为空!")
private Date birthday;
/**
* 经验等级 (0: 初级 1: 中级 2: 高级 3: 资深)。
*/
@ApiModelProperty(value = "经验等级 (0: 初级 1: 中级 2: 高级 3: 资深)", required = true)
@NotNull(message = "数据验证失败,经验等级不能为空!")
@ConstDictRef(constDictClass = ExpLevel.class, message = "数据验证失败,经验等级为无效值!")
@Column(name = "experience_level")
private Integer experienceLevel;
/**
* 总共充值学币数量。
*/
@ApiModelProperty(value = "总共充值学币数量", required = true)
@NotNull(message = "数据验证失败,充值学币不能为空!", groups = {UpdateGroup.class})
@Column(name = "total_coin")
private Integer totalCoin;
/**
* 可用学币数量。
*/
@ApiModelProperty(value = "可用学币数量", required = true)
@NotNull(message = "数据验证失败,剩余学币不能为空!", groups = {UpdateGroup.class})
@Column(name = "left_coin")
private Integer leftCoin;
/**
* 年级Id。
*/
@ApiModelProperty(value = "年级Id", required = true)
@NotNull(message = "数据验证失败,年级不能为空!")
@Column(name = "grade_id")
private Integer gradeId;
/**
* 校区Id。
*/
@ApiModelProperty(value = "校区Id", required = true)
@NotNull(message = "数据验证失败,所属校区不能为空!")
@Column(name = "school_id")
private Long schoolId;
/**
* 注册时间。
*/
@ApiModelProperty(value = "注册时间")
@Column(name = "register_time")
private Date registerTime;
/**
* 学生状态 (0: 正常 1: 锁定 2: 注销)。
*/
@ApiModelProperty(value = "学生状态 (0: 正常 1: 锁定 2: 注销)", required = true)
@NotNull(message = "数据验证失败,学生状态不能为空!", groups = {UpdateGroup.class})
@ConstDictRef(constDictClass = StudentStatus.class, message = "数据验证失败,学生状态为无效值!")
private Integer status;
/**
* birthday 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "birthday 范围过滤起始值(>=)")
@Transient
private String birthdayStart;
/**
* birthday 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "birthday 范围过滤结束值(<=)")
@Transient
private String birthdayEnd;
/**
* registerTime 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "registerTime 范围过滤起始值(>=)")
@Transient
private String registerTimeStart;
/**
* registerTime 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "registerTime 范围过滤结束值(<=)")
@Transient
private String registerTimeEnd;
/**
* login_mobile / student_name LIKE搜索字符串。
*/
@ApiModelProperty(value = "LIKE模糊搜索字符串")
@Transient
private String searchString;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "provinceId",
slaveServiceName = "areaCodeService",
slaveModelClass = AreaCode.class,
slaveIdField = "areaId",
slaveNameField = "areaName")
@Transient
private Map<String, Object> provinceIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "cityId",
slaveServiceName = "areaCodeService",
slaveModelClass = AreaCode.class,
slaveIdField = "areaId",
slaveNameField = "areaName")
@Transient
private Map<String, Object> cityIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "districtId",
slaveServiceName = "areaCodeService",
slaveModelClass = AreaCode.class,
slaveIdField = "areaId",
slaveNameField = "areaName")
@Transient
private Map<String, Object> districtIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "gradeId",
slaveServiceName = "gradeService",
slaveModelClass = Grade.class,
slaveIdField = "gradeId",
slaveNameField = "gradeName")
@Transient
private Map<String, Object> gradeIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "schoolId",
slaveServiceName = "schoolInfoService",
slaveModelClass = SchoolInfo.class,
slaveIdField = "schoolId",
slaveNameField = "schoolName")
@Transient
private Map<String, Object> schoolIdDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "gender",
constantDictClass = Gender.class)
@Transient
private Map<String, Object> genderDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "experienceLevel",
constantDictClass = ExpLevel.class)
@Transient
private Map<String, Object> experienceLevelDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "status",
constantDictClass = StudentStatus.class)
@Transient
private Map<String, Object> statusDictMap;
}

View File

@@ -0,0 +1,236 @@
package com.orange.demo.app.model;
import com.orange.demo.common.core.annotation.RelationDict;
import com.orange.demo.common.core.validator.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Map;
/**
* StudentActionStats实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("StudentActionStats实体对象")
@Data
@Table(name = "zz_student_action_stats")
public class StudentActionStats {
/**
* 主键Id。
*/
@ApiModelProperty(value = "主键Id", required = true)
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "stats_id")
private Long statsId;
/**
* 统计日期。
*/
@ApiModelProperty(value = "统计日期", required = true)
@NotNull(message = "数据验证失败,统计日期不能为空!")
@Column(name = "stats_date")
private Date statsDate;
/**
* 统计小时。
*/
@ApiModelProperty(value = "统计小时")
@Column(name = "stats_month")
private Date statsMonth;
/**
* 年级Id。
*/
@ApiModelProperty(value = "年级Id", required = true)
@NotNull(message = "数据验证失败,所属年级不能为空!")
@Column(name = "grade_id")
private Integer gradeId;
/**
* 学生所在省Id。
*/
@ApiModelProperty(value = "学生所在省Id", required = true)
@NotNull(message = "数据验证失败,所在省份不能为空!")
@Column(name = "province_id")
private Long provinceId;
/**
* 学生所在城市Id。
*/
@ApiModelProperty(value = "学生所在城市Id", required = true)
@NotNull(message = "数据验证失败,所在城市不能为空!", groups = {UpdateGroup.class})
@Column(name = "city_id")
private Long cityId;
/**
* 购课学币数量。
*/
@ApiModelProperty(value = "购课学币数量", required = true)
@NotNull(message = "数据验证失败,购课学币数量不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_course_amount")
private Integer buyCourseAmount;
/**
* 购买课程次数。
*/
@ApiModelProperty(value = "购买课程次数", required = true)
@NotNull(message = "数据验证失败,购买课程次数不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_course_count")
private Integer buyCourseCount;
/**
* 购买视频学币数量。
*/
@ApiModelProperty(value = "购买视频学币数量", required = true)
@NotNull(message = "数据验证失败,购买视频学币数量不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_video_amount")
private Integer buyVideoAmount;
/**
* 购买视频次数。
*/
@ApiModelProperty(value = "购买视频次数", required = true)
@NotNull(message = "数据验证失败,购买视频次数不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_video_count")
private Integer buyVideoCount;
/**
* 购买作业学币数量。
*/
@ApiModelProperty(value = "购买作业学币数量", required = true)
@NotNull(message = "数据验证失败,购买作业学币数量不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_paper_amount")
private Integer buyPaperAmount;
/**
* 购买作业次数。
*/
@ApiModelProperty(value = "购买作业次数", required = true)
@NotNull(message = "数据验证失败,购买作业次数不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_paper_count")
private Integer buyPaperCount;
/**
* 购买献花数量。
*/
@ApiModelProperty(value = "购买献花数量", required = true)
@NotNull(message = "数据验证失败,购买献花数量不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_flower_amount")
private Integer buyFlowerAmount;
/**
* 购买献花次数。
*/
@ApiModelProperty(value = "购买献花次数", required = true)
@NotNull(message = "数据验证失败,购买献花次数不能为空!", groups = {UpdateGroup.class})
@Column(name = "buy_flower_count")
private Integer buyFlowerCount;
/**
* 充值学币数量。
*/
@ApiModelProperty(value = "充值学币数量", required = true)
@NotNull(message = "数据验证失败,充值学币数量不能为空!", groups = {UpdateGroup.class})
@Column(name = "recharge_coin_amount")
private Integer rechargeCoinAmount;
/**
* 充值学币次数。
*/
@ApiModelProperty(value = "充值学币次数", required = true)
@NotNull(message = "数据验证失败,充值学币次数不能为空!", groups = {UpdateGroup.class})
@Column(name = "recharge_coin_count")
private Integer rechargeCoinCount;
/**
* 线下课程上课次数。
*/
@ApiModelProperty(value = "线下课程上课次数", required = true)
@NotNull(message = "数据验证失败,线下课程上课次数不能为空!")
@Column(name = "do_course_count")
private Integer doCourseCount;
/**
* 观看视频次数。
*/
@ApiModelProperty(value = "观看视频次数", required = true)
@NotNull(message = "数据验证失败,观看视频次数不能为空!", groups = {UpdateGroup.class})
@Column(name = "watch_video_count")
private Integer watchVideoCount;
/**
* 购买献花消费学币数量。
*/
@ApiModelProperty(value = "购买献花消费学币数量", required = true)
@NotNull(message = "数据验证失败,购买献花消费学币数量不能为空!")
@Column(name = "watch_video_total_second")
private Integer watchVideoTotalSecond;
/**
* 做题数量。
*/
@ApiModelProperty(value = "做题数量", required = true)
@NotNull(message = "数据验证失败,做题数量不能为空!", groups = {UpdateGroup.class})
@Column(name = "do_exercise_count")
private Integer doExerciseCount;
/**
* 做题正确的数量。
*/
@ApiModelProperty(value = "做题正确的数量", required = true)
@NotNull(message = "数据验证失败,做题正确的数量不能为空!", groups = {UpdateGroup.class})
@Column(name = "do_exercise_correct_count")
private Integer doExerciseCorrectCount;
/**
* statsDate 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "statsDate 范围过滤起始值(>=)")
@Transient
private String statsDateStart;
/**
* statsDate 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "statsDate 范围过滤结束值(<=)")
@Transient
private String statsDateEnd;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "gradeId",
slaveServiceName = "gradeService",
slaveModelClass = Grade.class,
slaveIdField = "gradeId",
slaveNameField = "gradeName")
@Transient
private Map<String, Object> gradeIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "provinceId",
slaveServiceName = "areaCodeService",
slaveModelClass = AreaCode.class,
slaveIdField = "areaId",
slaveNameField = "areaName")
@Transient
private Map<String, Object> provinceIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "cityId",
slaveServiceName = "areaCodeService",
slaveModelClass = AreaCode.class,
slaveIdField = "areaId",
slaveNameField = "areaName")
@Transient
private Map<String, Object> cityIdDictMap;
}

View File

@@ -0,0 +1,192 @@
package com.orange.demo.app.model;
import com.orange.demo.application.common.constant.StudentActionType;
import com.orange.demo.application.common.constant.DeviceType;
import com.orange.demo.common.core.annotation.RelationDict;
import com.orange.demo.common.core.annotation.RelationConstDict;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.common.core.validator.ConstDictRef;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Map;
/**
* StudentActionTrans实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("StudentActionTrans实体对象")
@Data
@Table(name = "zz_student_action_trans")
public class StudentActionTrans {
/**
* 主键Id。
*/
@ApiModelProperty(value = "主键Id", required = true)
@NotNull(message = "数据验证失败主键Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "trans_id")
private Long transId;
/**
* 学生Id。
*/
@ApiModelProperty(value = "学生Id", required = true)
@NotNull(message = "数据验证失败学生Id不能为空")
@Column(name = "student_id")
private Long studentId;
/**
* 学生名称。
*/
@ApiModelProperty(value = "学生名称", required = true)
@NotBlank(message = "数据验证失败,学生名称不能为空!")
@Column(name = "student_name")
private String studentName;
/**
* 学生校区。
*/
@ApiModelProperty(value = "学生校区", required = true)
@NotNull(message = "数据验证失败,学生校区不能为空!")
@Column(name = "school_id")
private Long schoolId;
/**
* 年级Id。
*/
@ApiModelProperty(value = "年级Id", required = true)
@NotNull(message = "数据验证失败,学生年级不能为空!")
@Column(name = "grade_id")
private Integer gradeId;
/**
* 行为类型(0: 充值 1: 购课 2: 上课签到 3: 上课签退 4: 看视频课 5: 做作业 6: 刷题 7: 献花)。
*/
@ApiModelProperty(value = "行为类型(0: 充值 1: 购课 2: 上课签到 3: 上课签退 4: 看视频课 5: 做作业 6: 刷题 7: 献花)", required = true)
@NotNull(message = "数据验证失败,行为类型不能为空!")
@ConstDictRef(constDictClass = StudentActionType.class, message = "数据验证失败,行为类型为无效值!")
@Column(name = "action_type")
private Integer actionType;
/**
* 设备类型(0: iOS 1: Android 2: PC)。
*/
@ApiModelProperty(value = "设备类型(0: iOS 1: Android 2: PC)", required = true)
@NotNull(message = "数据验证失败,设备类型不能为空!")
@ConstDictRef(constDictClass = DeviceType.class, message = "数据验证失败,设备类型为无效值!")
@Column(name = "device_type")
private Integer deviceType;
/**
* 看视频秒数。
*/
@ApiModelProperty(value = "看视频秒数")
@Column(name = "watch_video_seconds")
private Integer watchVideoSeconds;
/**
* 购买献花数量。
*/
@ApiModelProperty(value = "购买献花数量")
@Column(name = "flower_count")
private Integer flowerCount;
/**
* 购买作业数量。
*/
@ApiModelProperty(value = "购买作业数量")
@Column(name = "paper_count")
private Integer paperCount;
/**
* 购买视频数量。
*/
@ApiModelProperty(value = "购买视频数量")
@Column(name = "video_count")
private Integer videoCount;
/**
* 购买课程数量。
*/
@ApiModelProperty(value = "购买课程数量")
@Column(name = "course_count")
private Integer courseCount;
/**
* 充值学币数量。
*/
@ApiModelProperty(value = "充值学币数量")
@Column(name = "coin_count")
private Integer coinCount;
/**
* 做题是否正确标记。
*/
@ApiModelProperty(value = "做题是否正确标记")
@Column(name = "exercise_correct_flag")
private Integer exerciseCorrectFlag;
/**
* 发生时间。
*/
@ApiModelProperty(value = "发生时间", required = true)
@NotNull(message = "数据验证失败,发生时间不能为空!")
@Column(name = "create_time")
private Date createTime;
/**
* createTime 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "createTime 范围过滤起始值(>=)")
@Transient
private String createTimeStart;
/**
* createTime 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "createTime 范围过滤结束值(<=)")
@Transient
private String createTimeEnd;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "schoolId",
slaveServiceName = "schoolInfoService",
slaveModelClass = SchoolInfo.class,
slaveIdField = "schoolId",
slaveNameField = "schoolName")
@Transient
private Map<String, Object> schoolIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "gradeId",
slaveServiceName = "gradeService",
slaveModelClass = Grade.class,
slaveIdField = "gradeId",
slaveNameField = "gradeName")
@Transient
private Map<String, Object> gradeIdDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "actionType",
constantDictClass = StudentActionType.class)
@Transient
private Map<String, Object> actionTypeDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "deviceType",
constantDictClass = DeviceType.class)
@Transient
private Map<String, Object> deviceTypeDictMap;
}

View File

@@ -0,0 +1,128 @@
package com.orange.demo.app.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.orange.demo.app.model.constant.ClassLevel;
import com.orange.demo.common.core.annotation.RelationDict;
import com.orange.demo.common.core.annotation.RelationConstDict;
import com.orange.demo.common.core.annotation.DeletedFlagColumn;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.common.core.validator.ConstDictRef;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Map;
/**
* StudentClass实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("StudentClass实体对象")
@Data
@Table(name = "zz_class")
public class StudentClass {
/**
* 班级Id。
*/
@ApiModelProperty(value = "班级Id", required = true)
@NotNull(message = "数据验证失败班级Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "class_id")
private Long classId;
/**
* 班级名称。
*/
@ApiModelProperty(value = "班级名称", required = true)
@NotBlank(message = "数据验证失败,班级名称不能为空!")
@Column(name = "class_name")
private String className;
/**
* 学校Id。
*/
@ApiModelProperty(value = "学校Id", required = true)
@NotNull(message = "数据验证失败,所属校区不能为空!")
@Column(name = "school_id")
private Long schoolId;
/**
* 学生班长Id。
*/
@ApiModelProperty(value = "学生班长Id", required = true)
@NotNull(message = "数据验证失败,学生班长不能为空!")
@Column(name = "leader_id")
private Long leaderId;
/**
* 已完成课时数量。
*/
@ApiModelProperty(value = "已完成课时数量", required = true)
@NotNull(message = "数据验证失败,已完成课时不能为空!", groups = {UpdateGroup.class})
@Column(name = "finish_class_hour")
private Integer finishClassHour;
/**
* 班级级别(0: 初级班 1: 培优班 2: 冲刺提分班 3: 竞赛班)。
*/
@ApiModelProperty(value = "班级级别(0: 初级班 1: 培优班 2: 冲刺提分班 3: 竞赛班)", required = true)
@NotNull(message = "数据验证失败,班级级别不能为空!")
@ConstDictRef(constDictClass = ClassLevel.class, message = "数据验证失败,班级级别为无效值!")
@Column(name = "class_level")
private Integer classLevel;
/**
* 创建用户。
*/
@ApiModelProperty(value = "创建用户")
@Column(name = "create_user_id")
private Long createUserId;
/**
* 班级创建时间。
*/
@ApiModelProperty(value = "班级创建时间")
@Column(name = "create_time")
private Date createTime;
/**
* 逻辑删除标记字段(1: 正常 -1: 已删除)。
*/
@ApiModelProperty(hidden = true)
@JSONField(serialize = false)
@DeletedFlagColumn
private Integer status;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "schoolId",
slaveServiceName = "schoolInfoService",
slaveModelClass = SchoolInfo.class,
slaveIdField = "schoolId",
slaveNameField = "schoolName")
@Transient
private Map<String, Object> schoolIdDictMap;
@ApiModelProperty(hidden = true)
@RelationDict(
masterIdField = "leaderId",
slaveServiceName = "studentService",
slaveModelClass = Student.class,
slaveIdField = "studentId",
slaveNameField = "studentName")
@Transient
private Map<String, Object> leaderIdDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "classLevel",
constantDictClass = ClassLevel.class)
@Transient
private Map<String, Object> classLevelDictMap;
}

View File

@@ -0,0 +1,49 @@
package com.orange.demo.app.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 班级级别常量字典对象。
*
* @author Jerry
* @date 2020-09-24
*/
public final class ClassLevel {
/**
* 初级班。
*/
public static final int NORMAL = 0;
/**
* 中级班。
*/
public static final int MIDDLE = 1;
/**
* 高级班。
*/
public static final int HIGH = 2;
private static final Map<Object, String> DICT_MAP = new HashMap<>(3);
static {
DICT_MAP.put(NORMAL, "初级班");
DICT_MAP.put(MIDDLE, "中级班");
DICT_MAP.put(HIGH, "高级班");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private ClassLevel() {
}
}

View File

@@ -0,0 +1,44 @@
package com.orange.demo.app.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 班级状态常量字典对象。
*
* @author Jerry
* @date 2020-09-24
*/
public final class ClassStatus {
/**
* 正常。
*/
public static final int NORAML = 1;
/**
* 解散。
*/
public static final int DELETED = -1;
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
static {
DICT_MAP.put(NORAML, "正常");
DICT_MAP.put(DELETED, "解散");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private ClassStatus() {
}
}

View File

@@ -0,0 +1,49 @@
package com.orange.demo.app.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 课程难度常量字典对象。
*
* @author Jerry
* @date 2020-09-24
*/
public final class CourseDifficult {
/**
* 容易。
*/
public static final int NORMAL = 0;
/**
* 普通。
*/
public static final int MIDDLE = 1;
/**
* 困难。
*/
public static final int HIGH = 2;
private static final Map<Object, String> DICT_MAP = new HashMap<>(3);
static {
DICT_MAP.put(NORMAL, "容易");
DICT_MAP.put(MIDDLE, "普通");
DICT_MAP.put(HIGH, "困难");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private CourseDifficult() {
}
}

View File

@@ -0,0 +1,57 @@
package com.orange.demo.app.service;
import com.orange.demo.app.dao.AreaCodeMapper;
import com.orange.demo.app.model.AreaCode;
import com.orange.demo.common.core.cache.MapTreeDictionaryCache;
import com.orange.demo.common.core.base.service.BaseDictService;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import java.util.Collection;
import java.util.List;
/**
* 行政区划的Service类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class AreaCodeService extends BaseDictService<AreaCode, Long> {
@Autowired
private AreaCodeMapper areaCodeMapper;
public AreaCodeService() {
super();
this.dictionaryCache = MapTreeDictionaryCache.create(AreaCode::getAreaId, AreaCode::getParentId);
}
@Override
protected BaseDaoMapper<AreaCode> mapper() {
return areaCodeMapper;
}
/**
* 加载数据库数据到内存缓存。
*/
@Override
public void loadCachedData() {
Example e = new Example(AreaCode.class);
e.orderBy("areaLevel");
List<AreaCode> areaCodeList = areaCodeMapper.selectByExample(e);
dictionaryCache.putAll(areaCodeList);
}
/**
* 根据上级行政区划Id获取其下级行政区划列表。
*
* @param parentId 上级行政区划Id。
* @return 下级行政区划列表。
*/
public Collection<AreaCode> getListByParentId(Long parentId) {
return ((MapTreeDictionaryCache<Long, AreaCode>) dictionaryCache).getListByParentId(parentId);
}
}

View File

@@ -0,0 +1,175 @@
package com.orange.demo.app.service;
import com.orange.demo.app.dao.*;
import com.orange.demo.app.model.*;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.object.TokenData;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.object.CallResult;
import com.orange.demo.common.core.base.service.BaseService;
import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 课程数据数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class CourseService extends BaseService<Course, Long> {
@Autowired
private CourseMapper courseMapper;
@Autowired
private ClassCourseMapper classCourseMapper;
@Autowired
private GradeService gradeService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<Course> mapper() {
return courseMapper;
}
/**
* 保存新增对象。
*
* @param course 新增对象。
* @return 返回新增对象。
*/
@Transactional(rollbackFor = Exception.class)
public Course saveNew(Course course) {
course.setCourseId(idGenerator.nextLongId());
TokenData tokenData = TokenData.takeFromRequest();
course.setCreateUserId(tokenData.getUserId());
Date now = new Date();
course.setCreateTime(now);
course.setUpdateTime(now);
courseMapper.insert(course);
return course;
}
/**
* 更新数据对象。
*
* @param course 更新的对象。
* @param originalCourse 原有数据对象。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean update(Course course, Course originalCourse) {
course.setCreateUserId(originalCourse.getCreateUserId());
course.setCreateTime(originalCourse.getCreateTime());
course.setUpdateTime(new Date());
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
return courseMapper.updateByPrimaryKey(course) == 1;
}
/**
* 删除指定数据。
*
* @param courseId 主键Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean remove(Long courseId) {
// 这里先删除主数据
if (courseMapper.deleteByPrimaryKey(courseId) == 0) {
return false;
}
// 这里可继续删除关联数据。
// 开始删除多对多父表的关联
ClassCourse classCourse = new ClassCourse();
classCourse.setCourseId(courseId);
classCourseMapper.delete(classCourse);
return true;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getCourseListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Course> getCourseList(Course filter, String orderBy) {
return courseMapper.getCourseList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getCourseList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Course> getCourseListWithRelation(Course filter, String orderBy) {
List<Course> resultList = courseMapper.getCourseList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 在多对多关系中当前Service的数据表为从表返回不与指定主表主键Id存在对多对关系的列表。
*
* @param classId 主表主键Id。
* @param filter 从表的过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Course> getNotInCourseListByClassId(
Long classId, Course filter, String orderBy) {
List<Course> resultList =
courseMapper.getNotInCourseListByClassId(classId, filter, orderBy);
this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null);
return resultList;
}
/**
* 在多对多关系中当前Service的数据表为从表返回与指定主表主键Id存在对多对关系的列表。
*
* @param classId 主表主键Id。
* @param filter 从表的过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Course> getCourseListByClassId(
Long classId, Course filter, String orderBy) {
List<Course> resultList =
courseMapper.getCourseListByClassId(classId, filter, orderBy);
this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null);
return resultList;
}
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param course 最新数据对象。
* @param originalCourse 原有数据对象。
* @return 数据全部正确返回true否则false。
*/
public CallResult verifyRelatedData(Course course, Course originalCourse) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在请刷新后重试";
//这里是基于字典的验证。
if (this.needToVerify(course, originalCourse, Course::getGradeId)
&& !gradeService.existId(course.getGradeId())) {
return CallResult.error(String.format(errorMessageFormat, "所属年级"));
}
return CallResult.ok();
}
}

View File

@@ -0,0 +1,83 @@
package com.orange.demo.app.service;
import com.orange.demo.app.dao.*;
import com.orange.demo.app.model.*;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.base.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 课程统计数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class CourseTransStatsService extends BaseService<CourseTransStats, Long> {
@Autowired
private CourseTransStatsMapper courseTransStatsMapper;
@Autowired
private GradeService gradeService;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<CourseTransStats> mapper() {
return courseTransStatsMapper;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getCourseTransStatsListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<CourseTransStats> getCourseTransStatsList(CourseTransStats filter, String orderBy) {
return courseTransStatsMapper.getCourseTransStatsList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getCourseTransStatsList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<CourseTransStats> getCourseTransStatsListWithRelation(CourseTransStats filter, String orderBy) {
List<CourseTransStats> resultList = courseTransStatsMapper.getCourseTransStatsList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 获取分组过滤后的数据查询结果,以及关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
*
* @param filter 过滤对象。
* @param groupSelect 分组显示列表参数。位于SQL语句SELECT的后面。
* @param groupBy 分组参数。位于SQL语句的GROUP BY后面。
* @param orderBy 排序字符串ORDER BY从句的参数。
* @return 分组过滤结果集。
*/
public List<CourseTransStats> getGroupedCourseTransStatsListWithRelation(
CourseTransStats filter, String groupSelect, String groupBy, String orderBy) {
List<CourseTransStats> resultList =
courseTransStatsMapper.getGroupedCourseTransStatsList(filter, groupSelect, groupBy, orderBy);
// NOTE: 这里只是包含了关联数据,聚合计算数据没有包含。
// 主要原因是由于聚合字段通常被视为普通字段使用不会在group by的从句中出现语义上也不会在此关联。
this.buildRelationForDataList(resultList, MyRelationParam.normal(), null);
return resultList;
}
}

View File

@@ -0,0 +1,88 @@
package com.orange.demo.app.service;
import com.orange.demo.common.core.base.service.BaseDictService;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.cache.MapDictionaryCache;
import com.orange.demo.common.core.constant.GlobalDeletedFlag;
import com.orange.demo.app.dao.GradeMapper;
import com.orange.demo.app.model.Grade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 年级数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class GradeService extends BaseDictService<Grade, Integer> {
@Autowired
private GradeMapper gradeMapper;
public GradeService() {
super();
this.dictionaryCache = MapDictionaryCache.create(Grade::getGradeId);
}
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<Grade> mapper() {
return gradeMapper;
}
/**
* 保存新增对象。
*
* @param grade 新增对象。
* @return 返回新增对象。
*/
@Transactional(rollbackFor = Exception.class)
public Grade saveNew(Grade grade) {
grade.setStatus(GlobalDeletedFlag.NORMAL);
gradeMapper.insert(grade);
dictionaryCache.put(grade.getGradeId(), grade);
return grade;
}
/**
* 更新数据对象。
*
* @param grade 更新的对象。
* @param originalGrade 原有数据对象。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean update(Grade grade, Grade originalGrade) {
grade.setStatus(GlobalDeletedFlag.NORMAL);
if (gradeMapper.updateByPrimaryKey(grade) != 1) {
return false;
}
dictionaryCache.put(grade.getGradeId(), grade);
return true;
}
/**
* 删除指定数据。
*
* @param gradeId 主键Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean remove(Integer gradeId) {
Grade deletedObject = new Grade();
deletedObject.setGradeId(gradeId);
deletedObject.setStatus(GlobalDeletedFlag.DELETED);
if (gradeMapper.updateByPrimaryKeySelective(deletedObject) != 1) {
return false;
}
dictionaryCache.invalidate(gradeId);
return true;
}
}

View File

@@ -0,0 +1,128 @@
package com.orange.demo.app.service;
import com.orange.demo.app.dao.*;
import com.orange.demo.app.model.*;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.object.CallResult;
import com.orange.demo.common.core.base.service.BaseService;
import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 校区数据数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class SchoolInfoService extends BaseService<SchoolInfo, Long> {
@Autowired
private SchoolInfoMapper schoolInfoMapper;
@Autowired
private AreaCodeService areaCodeService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<SchoolInfo> mapper() {
return schoolInfoMapper;
}
/**
* 保存新增对象。
*
* @param schoolInfo 新增对象。
* @return 返回新增对象。
*/
@Transactional(rollbackFor = Exception.class)
public SchoolInfo saveNew(SchoolInfo schoolInfo) {
schoolInfo.setSchoolId(idGenerator.nextLongId());
schoolInfoMapper.insert(schoolInfo);
return schoolInfo;
}
/**
* 更新数据对象。
*
* @param schoolInfo 更新的对象。
* @param originalSchoolInfo 原有数据对象。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean update(SchoolInfo schoolInfo, SchoolInfo originalSchoolInfo) {
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
return schoolInfoMapper.updateByPrimaryKey(schoolInfo) == 1;
}
/**
* 删除指定数据。
*
* @param schoolId 主键Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean remove(Long schoolId) {
return schoolInfoMapper.deleteByPrimaryKey(schoolId) != 0;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getSchoolInfoListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<SchoolInfo> getSchoolInfoList(SchoolInfo filter, String orderBy) {
return schoolInfoMapper.getSchoolInfoList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getSchoolInfoList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<SchoolInfo> getSchoolInfoListWithRelation(SchoolInfo filter, String orderBy) {
List<SchoolInfo> resultList = schoolInfoMapper.getSchoolInfoList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param schoolInfo 最新数据对象。
* @param originalSchoolInfo 原有数据对象。
* @return 数据全部正确返回true否则false。
*/
public CallResult verifyRelatedData(SchoolInfo schoolInfo, SchoolInfo originalSchoolInfo) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在请刷新后重试";
//这里是基于字典的验证。
if (this.needToVerify(schoolInfo, originalSchoolInfo, SchoolInfo::getProvinceId)
&& !areaCodeService.existId(schoolInfo.getProvinceId())) {
return CallResult.error(String.format(errorMessageFormat, "所在省份"));
}
//这里是基于字典的验证。
if (this.needToVerify(schoolInfo, originalSchoolInfo, SchoolInfo::getCityId)
&& !areaCodeService.existId(schoolInfo.getCityId())) {
return CallResult.error(String.format(errorMessageFormat, "所在城市"));
}
return CallResult.ok();
}
}

View File

@@ -0,0 +1,85 @@
package com.orange.demo.app.service;
import com.orange.demo.app.dao.*;
import com.orange.demo.app.model.*;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.base.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 学生行为统计数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class StudentActionStatsService extends BaseService<StudentActionStats, Long> {
@Autowired
private StudentActionStatsMapper studentActionStatsMapper;
@Autowired
private GradeService gradeService;
@Autowired
private AreaCodeService areaCodeService;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<StudentActionStats> mapper() {
return studentActionStatsMapper;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getStudentActionStatsListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<StudentActionStats> getStudentActionStatsList(StudentActionStats filter, String orderBy) {
return studentActionStatsMapper.getStudentActionStatsList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getStudentActionStatsList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<StudentActionStats> getStudentActionStatsListWithRelation(StudentActionStats filter, String orderBy) {
List<StudentActionStats> resultList = studentActionStatsMapper.getStudentActionStatsList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 获取分组过滤后的数据查询结果,以及关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
*
* @param filter 过滤对象。
* @param groupSelect 分组显示列表参数。位于SQL语句SELECT的后面。
* @param groupBy 分组参数。位于SQL语句的GROUP BY后面。
* @param orderBy 排序字符串ORDER BY从句的参数。
* @return 分组过滤结果集。
*/
public List<StudentActionStats> getGroupedStudentActionStatsListWithRelation(
StudentActionStats filter, String groupSelect, String groupBy, String orderBy) {
List<StudentActionStats> resultList =
studentActionStatsMapper.getGroupedStudentActionStatsList(filter, groupSelect, groupBy, orderBy);
// NOTE: 这里只是包含了关联数据,聚合计算数据没有包含。
// 主要原因是由于聚合字段通常被视为普通字段使用不会在group by的从句中出现语义上也不会在此关联。
this.buildRelationForDataList(resultList, MyRelationParam.normal(), null);
return resultList;
}
}

View File

@@ -0,0 +1,130 @@
package com.orange.demo.app.service;
import com.orange.demo.app.dao.*;
import com.orange.demo.app.model.*;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.object.CallResult;
import com.orange.demo.common.core.base.service.BaseService;
import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 学生行为流水数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class StudentActionTransService extends BaseService<StudentActionTrans, Long> {
@Autowired
private StudentActionTransMapper studentActionTransMapper;
@Autowired
private SchoolInfoService schoolInfoService;
@Autowired
private GradeService gradeService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<StudentActionTrans> mapper() {
return studentActionTransMapper;
}
/**
* 保存新增对象。
*
* @param studentActionTrans 新增对象。
* @return 返回新增对象。
*/
@Transactional(rollbackFor = Exception.class)
public StudentActionTrans saveNew(StudentActionTrans studentActionTrans) {
studentActionTrans.setTransId(idGenerator.nextLongId());
studentActionTransMapper.insert(studentActionTrans);
return studentActionTrans;
}
/**
* 更新数据对象。
*
* @param studentActionTrans 更新的对象。
* @param originalStudentActionTrans 原有数据对象。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean update(StudentActionTrans studentActionTrans, StudentActionTrans originalStudentActionTrans) {
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
return studentActionTransMapper.updateByPrimaryKey(studentActionTrans) == 1;
}
/**
* 删除指定数据。
*
* @param transId 主键Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean remove(Long transId) {
return studentActionTransMapper.deleteByPrimaryKey(transId) != 0;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getStudentActionTransListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<StudentActionTrans> getStudentActionTransList(StudentActionTrans filter, String orderBy) {
return studentActionTransMapper.getStudentActionTransList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getStudentActionTransList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<StudentActionTrans> getStudentActionTransListWithRelation(StudentActionTrans filter, String orderBy) {
List<StudentActionTrans> resultList = studentActionTransMapper.getStudentActionTransList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param studentActionTrans 最新数据对象。
* @param originalStudentActionTrans 原有数据对象。
* @return 数据全部正确返回true否则false。
*/
public CallResult verifyRelatedData(StudentActionTrans studentActionTrans, StudentActionTrans originalStudentActionTrans) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在请刷新后重试";
//这里是基于字典的验证。
if (this.needToVerify(studentActionTrans, originalStudentActionTrans, StudentActionTrans::getSchoolId)
&& !schoolInfoService.existId(studentActionTrans.getSchoolId())) {
return CallResult.error(String.format(errorMessageFormat, "学生校区"));
}
//这里是基于字典的验证。
if (this.needToVerify(studentActionTrans, originalStudentActionTrans, StudentActionTrans::getGradeId)
&& !gradeService.existId(studentActionTrans.getGradeId())) {
return CallResult.error(String.format(errorMessageFormat, "学生年级"));
}
return CallResult.ok();
}
}

View File

@@ -0,0 +1,255 @@
package com.orange.demo.app.service;
import com.orange.demo.app.dao.*;
import com.orange.demo.app.model.*;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.constant.GlobalDeletedFlag;
import com.orange.demo.common.core.object.TokenData;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.object.CallResult;
import com.orange.demo.common.core.base.service.BaseService;
import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import java.util.*;
/**
* 班级数据数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class StudentClassService extends BaseService<StudentClass, Long> {
@Autowired
private StudentClassMapper studentClassMapper;
@Autowired
private ClassCourseMapper classCourseMapper;
@Autowired
private ClassStudentMapper classStudentMapper;
@Autowired
private SchoolInfoService schoolInfoService;
@Autowired
private StudentService studentService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<StudentClass> mapper() {
return studentClassMapper;
}
/**
* 保存新增对象。
*
* @param studentClass 新增对象。
* @return 返回新增对象。
*/
@Transactional(rollbackFor = Exception.class)
public StudentClass saveNew(StudentClass studentClass) {
studentClass.setClassId(idGenerator.nextLongId());
TokenData tokenData = TokenData.takeFromRequest();
studentClass.setCreateUserId(tokenData.getUserId());
studentClass.setCreateTime(new Date());
studentClass.setStatus(GlobalDeletedFlag.NORMAL);
if (studentClass.getFinishClassHour() == null) {
studentClass.setFinishClassHour(0);
}
studentClassMapper.insert(studentClass);
return studentClass;
}
/**
* 更新数据对象。
*
* @param studentClass 更新的对象。
* @param originalStudentClass 原有数据对象。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean update(StudentClass studentClass, StudentClass originalStudentClass) {
studentClass.setCreateUserId(originalStudentClass.getCreateUserId());
studentClass.setCreateTime(originalStudentClass.getCreateTime());
studentClass.setStatus(GlobalDeletedFlag.NORMAL);
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
return studentClassMapper.updateByPrimaryKey(studentClass) == 1;
}
/**
* 删除指定数据。
*
* @param classId 主键Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean remove(Long classId) {
Example studentClassExample = new Example(StudentClass.class);
Example.Criteria c = studentClassExample.createCriteria();
c.andEqualTo(super.idFieldName, classId);
c.andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
// 这里先删除主数据
StudentClass deletedObject = new StudentClass();
deletedObject.setStatus(GlobalDeletedFlag.DELETED);
if (studentClassMapper.updateByExampleSelective(deletedObject, studentClassExample) == 0) {
return false;
}
// 开始删除多对多子表的关联
ClassCourse classCourse = new ClassCourse();
classCourse.setClassId(classId);
classCourseMapper.delete(classCourse);
ClassStudent classStudent = new ClassStudent();
classStudent.setClassId(classId);
classStudentMapper.delete(classStudent);
return true;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getStudentClassListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<StudentClass> getStudentClassList(StudentClass filter, String orderBy) {
return studentClassMapper.getStudentClassList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getStudentClassList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<StudentClass> getStudentClassListWithRelation(StudentClass filter, String orderBy) {
List<StudentClass> resultList = studentClassMapper.getStudentClassList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 批量添加多对多关联关系。
*
* @param classCourseList 多对多关联表对象集合。
* @param classId 主表Id。
*/
@Transactional(rollbackFor = Exception.class)
public void addClassCourseList(List<ClassCourse> classCourseList, Long classId) {
for (ClassCourse classCourse : classCourseList) {
classCourse.setClassId(classId);
if (classCourse.getCourseOrder() == null) {
classCourse.setCourseOrder(0);
}
}
classCourseMapper.insertList(classCourseList);
}
/**
* 更新中间表数据。
*
* @param classCourse 中间表对象。
* @return 更新成功与否。
*/
@Transactional(rollbackFor = Exception.class)
public boolean updateClassCourse(ClassCourse classCourse) {
Example e = new Example(ClassCourse.class);
e.createCriteria()
.andEqualTo("classId", classCourse.getClassId())
.andEqualTo("courseId", classCourse.getCourseId());
return classCourseMapper.updateByExample(classCourse, e) > 0;
}
/**
* 获取中间表数据。
*
* @param classId 主表Id。
* @param courseId 从表Id。
* @return 中间表对象。
*/
public ClassCourse getClassCourse(Long classId, Long courseId) {
Example e = new Example(ClassCourse.class);
e.createCriteria()
.andEqualTo("classId", classId)
.andEqualTo("courseId", courseId);
return classCourseMapper.selectOneByExample(e);
}
/**
* 移除单条多对多关系。
*
* @param classId 主表Id。
* @param courseId 从表Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean removeClassCourse(Long classId, Long courseId) {
ClassCourse classCourse = new ClassCourse();
classCourse.setClassId(classId);
classCourse.setCourseId(courseId);
return classCourseMapper.delete(classCourse) > 0;
}
/**
* 批量添加多对多关联关系。
*
* @param classStudentList 多对多关联表对象集合。
* @param classId 主表Id。
*/
@Transactional(rollbackFor = Exception.class)
public void addClassStudentList(List<ClassStudent> classStudentList, Long classId) {
for (ClassStudent classStudent : classStudentList) {
classStudent.setClassId(classId);
}
classStudentMapper.insertList(classStudentList);
}
/**
* 移除单条多对多关系。
*
* @param classId 主表Id。
* @param studentId 从表Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean removeClassStudent(Long classId, Long studentId) {
ClassStudent classStudent = new ClassStudent();
classStudent.setClassId(classId);
classStudent.setStudentId(studentId);
return classStudentMapper.delete(classStudent) > 0;
}
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param studentClass 最新数据对象。
* @param originalStudentClass 原有数据对象。
* @return 数据全部正确返回true否则false。
*/
public CallResult verifyRelatedData(StudentClass studentClass, StudentClass originalStudentClass) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在请刷新后重试";
//这里是基于字典的验证。
if (this.needToVerify(studentClass, originalStudentClass, StudentClass::getSchoolId)
&& !schoolInfoService.existId(studentClass.getSchoolId())) {
return CallResult.error(String.format(errorMessageFormat, "所属校区"));
}
//这里是基于字典的验证。
if (this.needToVerify(studentClass, originalStudentClass, StudentClass::getLeaderId)
&& !studentService.existId(studentClass.getLeaderId())) {
return CallResult.error(String.format(errorMessageFormat, "学生班长"));
}
return CallResult.ok();
}
}

View File

@@ -0,0 +1,202 @@
package com.orange.demo.app.service;
import com.orange.demo.application.common.constant.StudentStatus;
import com.orange.demo.app.dao.*;
import com.orange.demo.app.model.*;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.object.CallResult;
import com.orange.demo.common.core.base.service.BaseService;
import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 学生数据数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class StudentService extends BaseService<Student, Long> {
@Autowired
private StudentMapper studentMapper;
@Autowired
private ClassStudentMapper classStudentMapper;
@Autowired
private AreaCodeService areaCodeService;
@Autowired
private GradeService gradeService;
@Autowired
private SchoolInfoService schoolInfoService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<Student> mapper() {
return studentMapper;
}
/**
* 保存新增对象。
*
* @param student 新增对象。
* @return 返回新增对象。
*/
@Transactional(rollbackFor = Exception.class)
public Student saveNew(Student student) {
student.setStudentId(idGenerator.nextLongId());
student.setRegisterTime(new Date());
if (student.getTotalCoin() == null) {
student.setTotalCoin(0);
}
if (student.getLeftCoin() == null) {
student.setLeftCoin(0);
}
if (student.getStatus() == null) {
student.setStatus(StudentStatus.NORMAL);
}
studentMapper.insert(student);
return student;
}
/**
* 更新数据对象。
*
* @param student 更新的对象。
* @param originalStudent 原有数据对象。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean update(Student student, Student originalStudent) {
student.setRegisterTime(originalStudent.getRegisterTime());
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
return studentMapper.updateByPrimaryKey(student) == 1;
}
/**
* 删除指定数据。
*
* @param studentId 主键Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean remove(Long studentId) {
// 这里先删除主数据
if (studentMapper.deleteByPrimaryKey(studentId) == 0) {
return false;
}
// 这里可继续删除关联数据。
// 开始删除多对多父表的关联
ClassStudent classStudent = new ClassStudent();
classStudent.setStudentId(studentId);
classStudentMapper.delete(classStudent);
return true;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getStudentListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Student> getStudentList(Student filter, String orderBy) {
return studentMapper.getStudentList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getStudentList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Student> getStudentListWithRelation(Student filter, String orderBy) {
List<Student> resultList = studentMapper.getStudentList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 在多对多关系中当前Service的数据表为从表返回不与指定主表主键Id存在对多对关系的列表。
*
* @param classId 主表主键Id。
* @param filter 从表的过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Student> getNotInStudentListByClassId(
Long classId, Student filter, String orderBy) {
List<Student> resultList =
studentMapper.getNotInStudentListByClassId(classId, filter, orderBy);
this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null);
return resultList;
}
/**
* 在多对多关系中当前Service的数据表为从表返回与指定主表主键Id存在对多对关系的列表。
*
* @param classId 主表主键Id。
* @param filter 从表的过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<Student> getStudentListByClassId(
Long classId, Student filter, String orderBy) {
List<Student> resultList =
studentMapper.getStudentListByClassId(classId, filter, orderBy);
this.buildRelationForDataList(resultList, MyRelationParam.dictOnly(), null);
return resultList;
}
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param student 最新数据对象。
* @param originalStudent 原有数据对象。
* @return 数据全部正确返回true否则false。
*/
public CallResult verifyRelatedData(Student student, Student originalStudent) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在请刷新后重试";
//这里是基于字典的验证。
if (this.needToVerify(student, originalStudent, Student::getProvinceId)
&& !areaCodeService.existId(student.getProvinceId())) {
return CallResult.error(String.format(errorMessageFormat, "所在省份"));
}
//这里是基于字典的验证。
if (this.needToVerify(student, originalStudent, Student::getCityId)
&& !areaCodeService.existId(student.getCityId())) {
return CallResult.error(String.format(errorMessageFormat, "所在城市"));
}
//这里是基于字典的验证。
if (this.needToVerify(student, originalStudent, Student::getDistrictId)
&& !areaCodeService.existId(student.getDistrictId())) {
return CallResult.error(String.format(errorMessageFormat, "所在区县"));
}
//这里是基于字典的验证。
if (this.needToVerify(student, originalStudent, Student::getGradeId)
&& !gradeService.existId(student.getGradeId())) {
return CallResult.error(String.format(errorMessageFormat, "年级"));
}
//这里是基于字典的验证。
if (this.needToVerify(student, originalStudent, Student::getSchoolId)
&& !schoolInfoService.existId(student.getSchoolId())) {
return CallResult.error(String.format(errorMessageFormat, "所属校区"));
}
return CallResult.ok();
}
}

View File

@@ -0,0 +1,46 @@
package com.orange.demo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 应用程序自定义的程序属性配置文件。
*
* @author Jerry
* @date 2020-09-24
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "application")
public class ApplicationConfig {
/**
* token的Http Request Header的key
*/
private String tokenHeaderKey;
/**
* token在过期之前但是已经需要被刷新时response返回的header信息的key。
*/
private String refreshedTokenHeaderKey;
/**
* token 加密用的密钥该值的长度最少10个字符(过短会报错)。
*/
private String tokenSigningKey;
/**
* 令牌的过期时间,单位毫秒
*/
private Long expiration;
/**
* 用户密码被重置之后的缺省密码
*/
private String defaultUserPassword;
/**
* 上传文件的基础目录
*/
private String uploadFileBaseDir;
/**
* 授信ip列表没有填写表示全部信任。多个ip之间逗号分隔如: http://10.10.10.1:8080,http://10.10.10.2:8080
*/
private String credentialIpList;
}

View File

@@ -0,0 +1,30 @@
package com.orange.demo.config;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import tk.mybatis.spring.annotation.MapperScan;
import javax.sql.DataSource;
/**
* 数据源配置Bean对象。
*
* @author Jerry
* @date 2020-09-24
*/
@Configuration
@EnableTransactionManagement
@MapperScan(value = {"com.orange.demo.*.dao"})
public class DataSourceConfig {
@Bean(initMethod = "init", destroyMethod = "close")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.druid")
public DataSource druidDataSource() {
return DruidDataSourceBuilder.create().build();
}
}

View File

@@ -0,0 +1,57 @@
package com.orange.demo.config;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import javax.servlet.Filter;
import java.nio.charset.StandardCharsets;
/**
* 这里主要配置Web的各种过滤器和监听器等Servlet容器组件。
*
* @author Jerry
* @date 2020-09-24
*/
@Configuration
public class FilterConfig {
/**
* 配置Ajax跨域过滤器。
*/
@Bean
public CorsFilter corsFilterRegistration(ApplicationConfig applicationConfig) {
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
if (StringUtils.isNotBlank(applicationConfig.getCredentialIpList())) {
String[] credentialIpList = StringUtils.split(applicationConfig.getCredentialIpList(), ",");
if (credentialIpList.length > 0) {
for (String ip : credentialIpList) {
corsConfiguration.addAllowedOrigin(ip);
}
}
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addExposedHeader(applicationConfig.getRefreshedTokenHeaderKey());
corsConfiguration.setAllowCredentials(true);
configSource.registerCorsConfiguration("/**", corsConfiguration);
}
return new CorsFilter(configSource);
}
@Bean
public FilterRegistrationBean<Filter> characterEncodingFilterRegistration() {
FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(
new org.springframework.web.filter.CharacterEncodingFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("encoding", StandardCharsets.UTF_8.name());
// forceEncoding强制response也被编码另外即使request中已经设置encodingforceEncoding也会重新设置
filterRegistrationBean.addInitParameter("forceEncoding", "true");
filterRegistrationBean.setAsyncSupported(true);
return filterRegistrationBean;
}
}

View File

@@ -0,0 +1,21 @@
package com.orange.demo.config;
import com.orange.demo.interceptor.AuthenticationInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 所有的项目拦截器都在这里集中配置
*
* @author Jerry
* @date 2020-09-24
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/admin/**");
}
}

View File

@@ -0,0 +1,103 @@
package com.orange.demo.interceptor;
import com.alibaba.fastjson.JSON;
import com.orange.demo.config.ApplicationConfig;
import com.orange.demo.common.core.annotation.NoAuthInterface;
import com.orange.demo.common.core.constant.ErrorCodeEnum;
import com.orange.demo.common.core.object.ResponseResult;
import com.orange.demo.common.core.object.TokenData;
import com.orange.demo.common.core.util.ApplicationContextHolder;
import com.orange.demo.common.core.util.JwtUtil;
import com.orange.demo.common.core.cache.SessionCacheHelper;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 登录用户Token验证、生成和权限验证的拦截器。
*
* @author Jerry
* @date 2020-09-24
*/
@Slf4j
public class AuthenticationInterceptor implements HandlerInterceptor {
private ApplicationConfig appConfig =
ApplicationContextHolder.getBean("applicationConfig");
private SessionCacheHelper cacheHelper =
ApplicationContextHolder.getBean("sessionCacheHelper");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String url = request.getRequestURI();
// 如果接口方法标记NoAuthInterface注解可以直接跳过Token鉴权验证这里主要为了测试接口方便
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
if (hm.getBeanType().getAnnotation(NoAuthInterface.class) != null
|| hm.getMethodAnnotation(NoAuthInterface.class) != null) {
return true;
}
}
String token = request.getHeader(appConfig.getTokenHeaderKey());
if (StringUtils.isBlank(token)) {
token = request.getParameter(appConfig.getTokenHeaderKey());
}
Claims c = JwtUtil.parseToken(token, appConfig.getTokenSigningKey());
if (JwtUtil.isNullOrExpired(c)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
this.outputResponseMessage(response,
ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已过期或尚未登录,请重新登录!"));
return false;
}
String sessionId = (String) c.get("sessionId");
TokenData tokenData = cacheHelper.getTokenData(sessionId);
if (tokenData == null) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
this.outputResponseMessage(response,
ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已失效,请重新登录!"));
return false;
}
TokenData.addToRequest(tokenData);
if (JwtUtil.needToRefresh(c)) {
String refreshedToken = JwtUtil.generateToken(c, appConfig.getExpiration(), appConfig.getTokenSigningKey());
response.addHeader(appConfig.getRefreshedTokenHeaderKey(), refreshedToken);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 这里需要空注解否则sonar会不happy。
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 这里需要空注解否则sonar会不happy。
}
private void outputResponseMessage(HttpServletResponse response, ResponseResult<Object> respObj) {
PrintWriter out;
try {
out = response.getWriter();
} catch (IOException e) {
log.error("Failed to call OutputResponseMessage.", e);
return;
}
response.setContentType("application/json; charset=utf-8");
out.print(JSON.toJSONString(respObj));
out.flush();
out.close();
}
}

View File

@@ -0,0 +1,142 @@
package com.orange.demo.upms.controller;
import com.alibaba.fastjson.JSONObject;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import lombok.extern.slf4j.Slf4j;
import com.orange.demo.config.ApplicationConfig;
import com.orange.demo.upms.service.*;
import com.orange.demo.upms.model.SysUser;
import com.orange.demo.upms.model.constant.SysUserStatus;
import com.orange.demo.upms.model.constant.SysUserType;
import com.orange.demo.common.core.annotation.NoAuthInterface;
import com.orange.demo.common.core.constant.ApplicationConstant;
import com.orange.demo.common.core.constant.ErrorCodeEnum;
import com.orange.demo.common.core.object.ResponseResult;
import com.orange.demo.common.core.object.TokenData;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.cache.SessionCacheHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
/**
* 登录接口控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiSupport(order = 1)
@Api(tags = "用户登录接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/login")
public class LoginController {
@Autowired
private SysUserService sysUserService;
@Autowired
private ApplicationConfig appConfig;
@Autowired
private SessionCacheHelper cacheHelper;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 登录接口。
*
* @param loginName 登录名。
* @param password 密码。
* @return 应答结果对象其中包括JWT的Token数据以及菜单列表。
*/
@ApiImplicitParams({
// 这里包含密码密文,仅用于方便开发期间的接口测试,集成测试和发布阶段,需要将当前注解去掉。
// 如果您重新生成了公钥和私钥请替换password的缺省值。
@ApiImplicitParam(name = "loginName", defaultValue = "admin"),
@ApiImplicitParam(name = "password", defaultValue = "IP3ccke3GhH45iGHB5qP9p7iZw6xUyj28Ju10rnBiPKOI35sc%2BjI7%2FdsjOkHWMfUwGYGfz8ik31HC2Ruk%2Fhkd9f6RPULTHj7VpFdNdde2P9M4mQQnFBAiPM7VT9iW3RyCtPlJexQ3nAiA09OqG%2F0sIf1kcyveSrulxembARDbDo%3D")
})
@NoAuthInterface
@GetMapping("/doLogin")
public ResponseResult<JSONObject> doLogin(
@RequestParam String loginName, @RequestParam String password) throws Exception {
if (MyCommonUtil.existBlankArgument(loginName, password)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
SysUser user = sysUserService.getSysUserByLoginName(loginName);
password = URLDecoder.decode(password, StandardCharsets.UTF_8.name());
//NOTE: 第一次使用时请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。
//执行RsaUtil工具类中的main函数可以生成新的公钥和私钥。
password = RsaUtil.decrypt(password, ApplicationConstant.PRIVATE_KEY);
if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD);
}
String errorMessage;
if (user.getUserStatus() == SysUserStatus.STATUS_LOCKED) {
errorMessage = "登录失败,用户账号被锁定!";
return ResponseResult.error(ErrorCodeEnum.INVALID_USER_STATUS, errorMessage);
}
boolean isAdmin = user.getUserType() == SysUserType.TYPE_ADMIN;
Map<String, Object> claims = new HashMap<>(3);
String sessionId = MyCommonUtil.generateUuid();
claims.put("sessionId", sessionId);
String token = JwtUtil.generateToken(claims, appConfig.getExpiration(), appConfig.getTokenSigningKey());
JSONObject jsonData = new JSONObject();
jsonData.put(TokenData.REQUEST_ATTRIBUTE_NAME, token);
jsonData.put("showName", user.getShowName());
jsonData.put("isAdmin", isAdmin);
TokenData tokenData = new TokenData();
tokenData.setSessionId(sessionId);
tokenData.setUserId(user.getUserId());
tokenData.setShowName(user.getShowName());
tokenData.setIsAdmin(isAdmin);
cacheHelper.putTokenData(sessionId, tokenData);
return ResponseResult.success(jsonData);
}
/**
* 登出操作。同时将Session相关的信息从缓存中删除。
*
* @return 应答结果对象。
*/
@PostMapping("/doLogout")
public ResponseResult<Void> doLogout() {
cacheHelper.removeAllSessionCache();
return ResponseResult.success();
}
/**
* 用户修改自己的密码。
*
* @param oldPass 原有密码。
* @param newPass 新密码。
* @return 应答结果对象。
*/
@PostMapping("/changePassword")
public ResponseResult<Void> changePassword(
@RequestParam String oldPass, @RequestParam String newPass) throws Exception {
if (MyCommonUtil.existBlankArgument(oldPass, oldPass)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
TokenData tokenData = TokenData.takeFromRequest();
SysUser user = sysUserService.getById(tokenData.getUserId());
oldPass = URLDecoder.decode(oldPass, StandardCharsets.UTF_8.name());
//NOTE: 第一次使用时请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。
//执行RsaUtil工具类中的main函数可以生成新的公钥和私钥。
oldPass = RsaUtil.decrypt(oldPass, ApplicationConstant.PRIVATE_KEY);
if (user == null || !passwordEncoder.matches(oldPass, user.getPassword())) {
return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD);
}
newPass = URLDecoder.decode(newPass, StandardCharsets.UTF_8.name());
newPass = RsaUtil.decrypt(newPass, ApplicationConstant.PRIVATE_KEY);
if (!sysUserService.changePassword(tokenData.getUserId(), newPass)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
}

View File

@@ -0,0 +1,177 @@
package com.orange.demo.upms.controller;
import com.github.pagehelper.page.PageMethod;
import com.orange.demo.upms.model.*;
import com.orange.demo.upms.service.*;
import com.orange.demo.common.core.object.*;
import com.orange.demo.common.core.util.*;
import com.orange.demo.common.core.constant.*;
import com.orange.demo.common.core.annotation.MyRequestBody;
import com.orange.demo.common.core.validator.AddGroup;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.config.ApplicationConfig;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
import javax.validation.groups.Default;
/**
* 用户管理操作控制器类。
*
* @author Jerry
* @date 2020-09-24
*/
@Api(tags = "用户管理管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/upms/sysUser")
public class SysUserController {
@Autowired
private SysUserService sysUserService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private ApplicationConfig appConfig;
/**
* 新增用户操作。
*
* @param sysUser 新增用户对象。
* @return 应答结果对象包含新增用户的主键Id。
*/
@ApiOperationSupport(ignoreParameters = {
"sysUser.userId",
"sysUser.createTimeStart",
"sysUser.createTimeEnd"})
@PostMapping("/add")
public ResponseResult<Long> add(@MyRequestBody SysUser sysUser) {
String errorMessage = MyCommonUtil.getModelValidationError(sysUser, Default.class, AddGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
CallResult result = sysUserService.verifyRelatedData(sysUser, null);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage());
}
sysUserService.saveNew(sysUser);
return ResponseResult.success(sysUser.getUserId());
}
/**
* 更新用户操作。
*
* @param sysUser 更新用户对象。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {
"sysUser.createTimeStart",
"sysUser.createTimeEnd"})
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody SysUser sysUser) {
String errorMessage = MyCommonUtil.getModelValidationError(sysUser, Default.class, UpdateGroup.class);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, errorMessage);
}
SysUser originalUser = sysUserService.getById(sysUser.getUserId());
if (originalUser == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
CallResult result = sysUserService.verifyRelatedData(sysUser, originalUser);
if (!result.isSuccess()) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATAED_FAILED, result.getErrorMessage());
}
if (!sysUserService.update(sysUser, originalUser)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 重置密码操作。
*
* @param userId 指定用户主键Id。
* @return 应答结果对象。
*/
@PostMapping("/resetPassword")
public ResponseResult<Void> resetPassword(@MyRequestBody Long userId) {
if (MyCommonUtil.existBlankArgument(userId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
if (!sysUserService.changePassword(userId, appConfig.getDefaultUserPassword())) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除用户管理数据。
*
* @param userId 删除对象主键Id。
* @return 应答结果对象。
*/
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long userId) {
String errorMessage;
if (MyCommonUtil.existBlankArgument(userId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 验证关联Id的数据合法性
SysUser originalSysUser = sysUserService.getById(userId);
if (originalSysUser == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!sysUserService.remove(userId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
/**
* 列出符合过滤条件的用户管理列表。
*
* @param sysUserFilter 过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<SysUser>> list(
@MyRequestBody SysUser sysUserFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class);
List<SysUser> resultList = sysUserService.getSysUserListWithRelation(sysUserFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(resultList));
}
/**
* 查看指定用户管理对象详情。
*
* @param userId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<SysUser> view(@RequestParam Long userId) {
if (MyCommonUtil.existBlankArgument(userId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
// 这里查看用户数据时候需要把用户多对多关联的角色和数据权限Id一并查出。
SysUser sysUser = sysUserService.getByIdWithRelation(userId, MyRelationParam.full());
if (sysUser == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success(sysUser);
}
}

View File

@@ -0,0 +1,26 @@
package com.orange.demo.upms.dao;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.upms.model.SysUser;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 用户管理数据操作访问接口。
*
* @author Jerry
* @date 2020-09-24
*/
public interface SysUserMapper extends BaseDaoMapper<SysUser> {
/**
* 获取过滤后的对象列表。
*
* @param sysUserFilter 主表过滤对象。
* @param orderBy 排序字符串order by从句的参数。
* @return 对象列表。
*/
List<SysUser> getSysUserList(
@Param("sysUserFilter") SysUser sysUserFilter, @Param("orderBy") String orderBy);
}

View File

@@ -0,0 +1,51 @@
<?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.orange.demo.upms.dao.SysUserMapper">
<resultMap id="BaseResultMap" type="com.orange.demo.upms.model.SysUser">
<id column="user_id" jdbcType="BIGINT" property="userId"/>
<result column="login_name" jdbcType="VARCHAR" property="loginName"/>
<result column="password" jdbcType="VARCHAR" property="password"/>
<result column="show_name" jdbcType="VARCHAR" property="showName"/>
<result column="user_type" jdbcType="INTEGER" property="userType"/>
<result column="head_image_url" jdbcType="VARCHAR" property="headImageUrl"/>
<result column="user_status" jdbcType="INTEGER" property="userStatus"/>
<result column="deleted_flag" jdbcType="INTEGER" property="deletedFlag"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_username" jdbcType="VARCHAR" property="createUsername"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
</resultMap>
<sql id="filterRef">
<if test="sysUserFilter != null">
<if test="sysUserFilter.loginName != null and sysUserFilter.loginName != ''">
<bind name = "safeLoginName" value = "'%' + sysUserFilter.loginName + '%'" />
AND zz_sys_user.login_name LIKE #{safeLoginName}
</if>
<if test="sysUserFilter.showName != null and sysUserFilter.showName != ''">
<bind name = "safeShowName" value = "'%' + sysUserFilter.showName + '%'" />
AND zz_sys_user.show_name LIKE #{safeShowName}
</if>
<if test="sysUserFilter.userStatus != null">
AND zz_sys_user.user_status = #{sysUserFilter.userStatus}
</if>
<if test="sysUserFilter.createTimeStart != null and sysUserFilter.createTimeStart != ''">
AND zz_sys_user.create_time &gt;= #{sysUserFilter.createTimeStart}
</if>
<if test="sysUserFilter.createTimeEnd != null and sysUserFilter.createTimeEnd != ''">
AND zz_sys_user.create_time &lt;= #{sysUserFilter.createTimeEnd}
</if>
</if>
AND zz_sys_user.deleted_flag = ${@com.orange.demo.common.core.constant.GlobalDeletedFlag@NORMAL}
</sql>
<select id="getSysUserList" resultMap="BaseResultMap" parameterType="com.orange.demo.upms.model.SysUser">
SELECT * FROM zz_sys_user
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>

View File

@@ -0,0 +1,152 @@
package com.orange.demo.upms.model;
import com.alibaba.fastjson.annotation.JSONField;
import com.orange.demo.upms.model.constant.SysUserType;
import com.orange.demo.upms.model.constant.SysUserStatus;
import com.orange.demo.common.core.annotation.RelationConstDict;
import com.orange.demo.common.core.annotation.DeletedFlagColumn;
import com.orange.demo.common.core.validator.AddGroup;
import com.orange.demo.common.core.validator.UpdateGroup;
import com.orange.demo.common.core.validator.ConstDictRef;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.*;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.Map;
/**
* SysUser实体对象。
*
* @author Jerry
* @date 2020-09-24
*/
@ApiModel("SysUser实体对象")
@Data
@Table(name = "zz_sys_user")
public class SysUser {
/**
* 用户Id。
*/
@ApiModelProperty(value = "用户Id", required = true)
@NotNull(message = "数据验证失败用户Id不能为空", groups = {UpdateGroup.class})
@Id
@Column(name = "user_id")
private Long userId;
/**
* 登录用户名。
*/
@ApiModelProperty(value = "登录用户名", required = true)
@NotBlank(message = "数据验证失败,登录用户名不能为空!")
@Column(name = "login_name")
private String loginName;
/**
* 用户密码。
*/
@ApiModelProperty(value = "用户密码", required = true)
@NotBlank(message = "数据验证失败,用户密码不能为空!", groups = {AddGroup.class})
private String password;
/**
* 用户显示名称。
*/
@ApiModelProperty(value = "用户显示名称", required = true)
@NotBlank(message = "数据验证失败,用户显示名称不能为空!")
@Column(name = "show_name")
private String showName;
/**
* 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。
*/
@ApiModelProperty(value = "用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)", required = true)
@NotNull(message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)不能为空!")
@ConstDictRef(constDictClass = SysUserType.class, message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)为无效值!")
@Column(name = "user_type")
private Integer userType;
/**
* 用户头像的Url。
*/
@ApiModelProperty(value = "用户头像的Url")
@Column(name = "head_image_url")
private String headImageUrl;
/**
* 用户状态(0: 正常 1: 锁定)。
*/
@ApiModelProperty(value = "用户状态(0: 正常 1: 锁定)", required = true)
@NotNull(message = "数据验证失败,用户状态(0: 正常 1: 锁定)不能为空!")
@ConstDictRef(constDictClass = SysUserStatus.class, message = "数据验证失败,用户状态(0: 正常 1: 锁定)为无效值!")
@Column(name = "user_status")
private Integer userStatus;
/**
* 逻辑删除标记字段(1: 正常 -1: 已删除)。
*/
@ApiModelProperty(hidden = true)
@JSONField(serialize = false)
@DeletedFlagColumn
@Column(name = "deleted_flag")
private Integer deletedFlag;
/**
* 创建用户Id。
*/
@ApiModelProperty(value = "创建用户Id")
@Column(name = "create_user_id")
private Long createUserId;
/**
* 创建用户名。
*/
@ApiModelProperty(value = "创建用户名")
@Column(name = "create_username")
private String createUsername;
/**
* 创建时间。
*/
@ApiModelProperty(value = "创建时间")
@Column(name = "create_time")
private Date createTime;
/**
* 更新时间。
*/
@ApiModelProperty(value = "更新时间")
@Column(name = "update_time")
private Date updateTime;
/**
* createTime 范围过滤起始值(>=)。
*/
@ApiModelProperty(value = "createTime 范围过滤起始值(>=)")
@Transient
private String createTimeStart;
/**
* createTime 范围过滤结束值(<=)。
*/
@ApiModelProperty(value = "createTime 范围过滤结束值(<=)")
@Transient
private String createTimeEnd;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "userType",
constantDictClass = SysUserType.class)
@Transient
private Map<String, Object> userTypeDictMap;
@ApiModelProperty(hidden = true)
@RelationConstDict(
masterIdField = "userStatus",
constantDictClass = SysUserStatus.class)
@Transient
private Map<String, Object> userStatusDictMap;
}

View File

@@ -0,0 +1,44 @@
package com.orange.demo.upms.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 用户状态常量字典对象。
*
* @author Jerry
* @date 2020-09-24
*/
public final class SysUserStatus {
/**
* 正常状态。
*/
public static final int STATUS_NORMAL = 0;
/**
* 锁定状态。
*/
public static final int STATUS_LOCKED = 1;
private static final Map<Object, String> DICT_MAP = new HashMap<>(2);
static {
DICT_MAP.put(STATUS_NORMAL, "正常状态");
DICT_MAP.put(STATUS_LOCKED, "锁定状态");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private SysUserStatus() {
}
}

View File

@@ -0,0 +1,49 @@
package com.orange.demo.upms.model.constant;
import java.util.HashMap;
import java.util.Map;
/**
* 用户类型常量字典对象。
*
* @author Jerry
* @date 2020-09-24
*/
public final class SysUserType {
/**
* 管理员。
*/
public static final int TYPE_ADMIN = 0;
/**
* 系统操作员。
*/
public static final int TYPE_SYSTEM = 1;
/**
* 普通操作员。
*/
public static final int TYPE_OPERATOR = 2;
private static final Map<Object, String> DICT_MAP = new HashMap<>(3);
static {
DICT_MAP.put(TYPE_ADMIN, "管理员");
DICT_MAP.put(TYPE_SYSTEM, "系统操作员");
DICT_MAP.put(TYPE_OPERATOR, "普通操作员");
}
/**
* 判断参数是否为当前常量字典的合法值。
*
* @param value 待验证的参数值。
* @return 合法返回true否则false。
*/
public static boolean isValid(Integer value) {
return value != null && DICT_MAP.containsKey(value);
}
/**
* 私有构造函数,明确标识该常量类的作用。
*/
private SysUserType() {
}
}

View File

@@ -0,0 +1,175 @@
package com.orange.demo.upms.service;
import com.alibaba.fastjson.JSONObject;
import com.orange.demo.upms.dao.*;
import com.orange.demo.upms.model.*;
import com.orange.demo.upms.model.constant.SysUserStatus;
import com.orange.demo.common.core.base.dao.BaseDaoMapper;
import com.orange.demo.common.core.constant.GlobalDeletedFlag;
import com.orange.demo.common.core.object.TokenData;
import com.orange.demo.common.core.object.MyWhereCriteria;
import com.orange.demo.common.core.object.MyRelationParam;
import com.orange.demo.common.core.object.CallResult;
import com.orange.demo.common.core.base.service.BaseService;
import com.orange.demo.common.sequence.wrapper.IdGeneratorWrapper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;
import java.util.*;
/**
* 用户管理数据操作服务类。
*
* @author Jerry
* @date 2020-09-24
*/
@Service
public class SysUserService extends BaseService<SysUser, Long> {
@Autowired
private SysUserMapper sysUserMapper;
@Autowired
private IdGeneratorWrapper idGenerator;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<SysUser> mapper() {
return sysUserMapper;
}
/**
* 获取指定登录名的用户对象。
*
* @param loginName 指定登录用户名。
* @return 用户对象。
*/
public SysUser getSysUserByLoginName(String loginName) {
Example e = new Example(SysUser.class);
Example.Criteria c = e.createCriteria();
c.andEqualTo("loginName", loginName);
c.andEqualTo("deletedFlag", GlobalDeletedFlag.NORMAL);
return sysUserMapper.selectOneByExample(e);
}
/**
* 保存新增的用户对象。
*
* @param user 新增的用户对象。
* @return 新增后的用户对象。
*/
@Transactional(rollbackFor = Exception.class)
public SysUser saveNew(SysUser user) {
user.setUserId(idGenerator.nextLongId());
user.setPassword(passwordEncoder.encode(user.getPassword()));
user.setUserStatus(SysUserStatus.STATUS_NORMAL);
user.setDeletedFlag(GlobalDeletedFlag.NORMAL);
TokenData tokenData = TokenData.takeFromRequest();
user.setCreateUserId(tokenData.getUserId());
user.setCreateUsername(tokenData.getShowName());
Date now = new Date();
user.setCreateTime(now);
user.setUpdateTime(now);
sysUserMapper.insert(user);
return user;
}
/**
* 更新用户对象。
*
* @param user 更新的用户对象。
* @param originalUser 原有的用户对象。
* @return 更新成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean update(SysUser user, SysUser originalUser) {
user.setLoginName(originalUser.getLoginName());
user.setPassword(originalUser.getPassword());
user.setCreateUserId(originalUser.getCreateUserId());
user.setCreateUsername(originalUser.getCreateUsername());
user.setCreateTime(originalUser.getCreateTime());
user.setUpdateTime(new Date());
return sysUserMapper.updateByPrimaryKeySelective(user) == 1;
}
/**
* 修改用户密码。
* @param userId 用户主键Id。
* @param newPass 新密码。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean changePassword(Long userId, String newPass) {
Example e = new Example(SysUser.class);
e.createCriteria().andEqualTo(super.idFieldName, userId);
e.createCriteria().andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
SysUser updatedUser = new SysUser();
updatedUser.setPassword(passwordEncoder.encode(newPass));
return sysUserMapper.updateByExampleSelective(updatedUser, e) == 1;
}
/**
* 删除指定数据。
*
* @param userId 主键Id。
* @return 成功返回true否则false。
*/
@Transactional(rollbackFor = Exception.class)
public boolean remove(Long userId) {
Example sysUserExample = new Example(SysUser.class);
Example.Criteria c = sysUserExample.createCriteria();
c.andEqualTo(super.idFieldName, userId);
c.andEqualTo(super.deletedFlagFieldName, GlobalDeletedFlag.NORMAL);
// 这里先删除主数据
SysUser deletedObject = new SysUser();
deletedObject.setDeletedFlag(GlobalDeletedFlag.DELETED);
return sysUserMapper.updateByExampleSelective(deletedObject, sysUserExample) != 0;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getSysUserListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<SysUser> getSysUserList(SysUser filter, String orderBy) {
return sysUserMapper.getSysUserList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 如果仅仅需要获取主表数据,请移步(getSysUserList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
public List<SysUser> getSysUserListWithRelation(SysUser filter, String orderBy) {
List<SysUser> resultList = sysUserMapper.getSysUserList(filter, orderBy);
Map<String, List<MyWhereCriteria>> criteriaMap = buildAggregationAdditionalWhereCriteria();
this.buildRelationForDataList(resultList, MyRelationParam.normal(), criteriaMap);
return resultList;
}
/**
* 验证用户对象关联的数据是否都合法。
*
* @param sysUser 当前操作的对象。
* @param originalSysUser 原有对象。
* @return 验证结果。
*/
public CallResult verifyRelatedData(SysUser sysUser, SysUser originalSysUser) {
JSONObject jsonObject = new JSONObject();
return CallResult.ok(jsonObject);
}
}

View File

@@ -0,0 +1,202 @@
logging:
level:
# 这里设置的日志级别优先于log4j2.xml文件Loggers中的日志级别。
com.orange.demo: info
server:
tomcat:
uri-encoding: UTF-8
max-threads: 100
min-spare-threads: 10
port: 8082
# spring相关配置
spring:
application:
name: application
profiles:
active: dev
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
http:
converters:
preferred-json-mapper: fastjson
encoding:
force: true
charset: UTF-8
enabled: true
freemarker:
template-loader-path: classpath:/template/
cache: false
charset: UTF-8
check-template-location: true
content-type: text/html
expose-request-attributes: false
expose-session-attributes: false
request-context-attribute: request
suffix: .ftl
# mybatis的基本配置
mybatis:
mapperLocations: classpath:com/orange/demo/*/dao/mapper/*Mapper.xml
typeAliasesPackage: com.orange.demo.*.model
# mybatis的通用mapper的配置
mapper:
mappers: tk.mybatis.mapper.common.Mapper,tk.mybatis.mapper.additional.insert.InsertListMapper
not-empty: false
identity: MYSQL
# 自动分页的配置
pagehelper:
helperDialect: mysql
reasonable: true
supportMethodsArguments: false
params: count=countSql
swagger:
# 当enabled为false的时候则可禁用swagger。
enabled: true
# 工程的基础包名。
basePackage: com.orange.demo
title: 橙单单体开源版
description: 橙单单体开源版详情
version: 1.0
# 暴露监控端点
management:
endpoints:
web:
exposure:
include: '*'
jmx:
exposure:
include: '*'
endpoint:
# 与中间件相关的健康详情也会被展示
health:
show-details: always
configprops:
# 在/actuator/configprops中所有包含password的配置将用 * 隐藏。
# 如果不想隐藏任何配置项的值,可以直接使用如下被注释的空值。
# keys-to-sanitize:
keys-to-sanitize: password
server:
servlet:
context-path: "/"
# 开发数据库相关配置
---
spring:
profiles: dev
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
url: jdbc:mysql://localhost:3306/zzdemo-single?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
name: application
initialSize: 10
minIdle: 10
maxActive: 50
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
maxOpenPreparedStatements: 20
validationQuery: SELECT 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
filters: stat,wall
useGlobalDataSourceStat: true
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*"
stat-view-servlet:
enabled: true
urlPattern: /druid/*
resetEnable: true
application:
# Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。
tokenSigningKey: OrangeSingleDemo-signing-key
# Jwt令牌在Http Header中的键名称。
tokenHeaderKey: Authorization
# Jwt令牌刷新后在Http Header中的键名称。
refreshedTokenHeaderKey: RefreshedToken
# Jwt令牌过期时间(毫秒)。
expiration: 72000000
# 初始化密码。
defaultUserPassword: 123456
# 缺省的文件上传根目录。
uploadFileBaseDir: ./zz-resource/upload-files/app
# 跨域的IP白名单列表多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。
credentialIpList: "*"
sequence:
# Snowflake 分布式Id生成算法所需的WorkNode参数值。
snowflakeWorkNode: 1
# 发布数据库相关配置
---
spring:
profiles: product
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
url: jdbc:mysql://localhost:3306/zzdemo-single?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
name: application
initialSize: 10
minIdle: 10
maxActive: 50
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
maxOpenPreparedStatements: 20
validationQuery: SELECT 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
filters: stat,wall
useGlobalDataSourceStat: true
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*"
stat-view-servlet:
enabled: true
urlPattern: /druid/*
resetEnable: true
application:
# Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。
tokenSigningKey: OrangeSingleDemo-signing-key
# Jwt令牌在Http Header中的键名称。
tokenHeaderKey: Authorization
# Jwt令牌刷新后在Http Header中的键名称。
refreshedTokenHeaderKey: RefreshedToken
# Jwt令牌过期时间(毫秒)。
expiration: 72000000
# 初始化密码。
defaultUserPassword: 123456
# 缺省的文件上传根目录。
uploadFileBaseDir: ./zz-resource/upload-files/app
# 跨域的IP白名单列表多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。
credentialIpList: "*"
sequence:
# Snowflake 分布式Id生成算法所需的WorkNode参数值。
snowflakeWorkNode: 1

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 本项目全部使用log4j2性能上有很大提升 -->
<!--monitorInterval="60" 自动检测配置文件更改时间 单位为秒 最小值为5 -->
<!--Configuration后面的status这个用于设置log4j2自身内部的信息输出可以不设置当设置成trace时你会看到log4j2内部各种详细输出。 -->
<configuration monitorInterval="20" status="OFF">
<!--日志变量 -->
<properties>
<!-- 日志主目录 ,需要保存到文件时请自己配置-->
<property name="LOG_HOME">./zzlogs</property>
<!-- 日志备份目录 -->
<property name="BACKUP_HOME">./zzlogs/backup</property>
<!-- 日志输出级别 -->
<property name="OUTPUT_LOG_LEVEL">info</property>
<!-- 日志输出格式 -->
<property name="LOG_PATTERN">
<!-- 输出格式%d{HH:mm:ss}时间24小时制 -->
<!-- %-5p日志级别 5位左对齐 [%t]线程名 [%c]类名 -->
<!--%l输出日志事件的发生位置相当于%c.%M(%F:%L)的组合包括类全名、方法、文件名以及在代码中的行数。例如test.TestLog4j.main(TestLog4j.java:10)。 -->
<!-- 另一种输出风格<PatternLayout pattern="级别%-5p [%d{YYYY-MM-dd HH:mm:ss}] [%t] 位置[%l] - 信息:%msg%n" /> -->
<!-- [%-5p][%d{yy-MM-dd HH:mm:ss}][%t]==>%m==>%c==>%L%n -->
[%-5p] [%d{YYYY-MM-dd HH:mm:ss}] [%t] ==> %msg%n
</property>
<property name="LOG_PATTERN_EX">
[%-5p] [%d{YYYY-MM-dd HH:mm:ss}] 请求Id[%X{traceId}] [%t] ==> %msg%n
</property>
<!-- 日志保留天数 -->
<property name="EVERY_FILE_COUNT">31</property>
<!-- 日志切割的最小单位 -->
<property name="EVERY_FILE_SIZE">20M</property>
</properties>
<appenders>
<!--控制台输出 -->
<console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}"/>
</console>
<!-- console_log级别日志文件 -->
<!--每次大小超过size则这size大小的日志会自动进行压缩作为存档 -->
<rollingFile name="file_log" fileName="${LOG_HOME}/server/server.log"
filePattern="${LOG_HOME}/server/server-%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout charset="UTF-8" pattern="${LOG_PATTERN_EX}"/>
<!-- 日志切割的最小单位 -->
<SizeBasedTriggeringPolicy size="${EVERY_FILE_SIZE}"/>
<!-- 默认的日志文件数量 -->
<DefaultRolloverStrategy max="${EVERY_FILE_COUNT}"/>
</rollingFile>
</appenders>
<!-- 然后定义logger只有定义了logger并引入的appenderappender才会生效 -->
<!-- 这里我们把输出到控制台appender的日志级别设置为DEBUG便于调试。但是输出文件我们缺省为INFO两者均可随时修改。-->
<Loggers>
<root level="${OUTPUT_LOG_LEVEL}">
<AppenderRef ref="console"/>
</root>
<Logger name="springfox.documentation" additivity="false" level="error">
<AppenderRef ref="console"/>
</Logger>
<Logger name="com.orange.demo" additivity="false" level="info">
<AppenderRef ref="console"/>
<AppenderRef ref="file_log"/>
</Logger>
<!-- 这里将dao的日志级别设置为DEBUG是为了SQL语句的输出 -->
<Logger name="com.orange.demo.app.dao" additivity="false" level="debug">
<AppenderRef ref="console"/>
<AppenderRef ref="file_log"/>
</Logger>
<Logger name="com.orange.demo.upms.dao" additivity="false" level="debug">
<AppenderRef ref="console"/>
<AppenderRef ref="file_log"/>
</Logger>
</Loggers>
</configuration>

View File

@@ -0,0 +1,329 @@
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
.b1{white-space-collapsing:preserve;}
.t1{border-collapse:collapse;border-spacing:0;}
.r1{height:23.25pt;}
.r2{height:18.75pt;}
.r3{height:17.25pt;}
.r4{height:15.0pt;}
.r5{height:14.25pt;}
.r6{height:21.0pt;}
.r7{height:18.0pt;}
.r8{height:15.75pt;}
.r9{height:19.5pt;}
.r10{height:17.0pt;}
.r11{height:20.25pt;}
.r12{height:28.5pt;}
.c1{white-space:pre-wrap;text-align:center;border-bottom:thin solid black;font-weight:bold;color: #dd0806; font-size:18pt;}
.c2{white-space:pre-wrap;text-align:center;background-color:#ffff00;border-top:thin solid black;border-left:thin solid black;color: #dd0806; font-size:12pt;}
.c3{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-left:thin solid black;color: #dd0806; font-size:12pt;}
.c4{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;color: #dd0806; font-size:12pt;}
.c5{white-space:pre-wrap;text-align:center;color: #dd0806; font-size:10pt;}
.c6{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;color: #dd0806; font-size:10pt;}
.c7{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;color: #dd0806; font-size:10pt;}
.c8{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:9pt;}
.c9{white-space:pre-wrap;text-align:center;background-color:#ffff00;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;color: #dd0806; font-size:11pt;}
.c10{white-space:pre-wrap;text-align:center;border-right:thin solid black;border-left:thin solid black;font-size:10pt;}
.c11{white-space:pre-wrap;text-align:center;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:10pt;}
.c12{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-left:thin solid black;font-size:10pt;}
.c13{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:8pt;}
.c14{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-left:thin solid black;font-size:8pt;}
.c15{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:10pt;}
.c16{white-space:pre-wrap;text-align:center;background-color:#ffff00;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:11pt;}
.c17{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:11pt;}
.c18{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:6pt;}
.c19{white-space:pre-wrap;text-align:center;border-right:thin solid black;border-bottom:thin solid black;border-left:thin solid black;font-size:6pt;}
.c20{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-left:thin solid black;font-weight:bold;font-size:6pt;}
.c21{white-space:pre-wrap;text-align:center;border-top:thin solid black;border-right:thin solid black;border-left:thin solid black;font-weight:bold;font-size:8pt;}
.c22{white-space:pre-wrap;text-align:left;border-top:thin solid black;font-weight:bold;font-size:9pt;}
</style>
</head>
<body class="b1">
<table class="t1">
<colgroup>
<col width="40">
<col width="40">
<col width="57">
<col width="57">
<col width="57">
<col width="57">
<col width="57">
<col width="56">
<col width="59">
<col width="57">
<col width="57">
<col width="57">
<col width="57">
<col width="57">
<col width="57">
<col width="57">
</colgroup>
<tbody>
<tr class="r1">
<td class="c1" colspan="16">天津公安警官职业学院2017—2018学年度第一学期课程表</td>
</tr>
<tr class="r1">
<td class="c2" colspan="2" rowspan="2">班 级</td>
<td class="c3" colspan="3">星期一</td>
<td class="c4" colspan="3">星期二</td>
<td class="c4" colspan="3">星期三</td>
<td class="c4" colspan="3">星期四</td>
<td class="c4" colspan="2">星期五</td>
</tr>
<tr class="r2">
<td class="c5">第1节</td>
<td class="c5">第2节</td>
<td class="c5">第3节</td>
<td class="c6">第1节</td>
<td class="c7">第2节</td>
<td class="c7">第3节</td>
<td class="c7">第1节</td>
<td class="c7">第2节</td>
<td class="c7">第3节</td>
<td class="c7">第1节</td>
<td class="c7">第2节</td>
<td class="c7">第3节</td>
<td class="c7">第1节</td>
<td class="c7">第2节</td>
</tr>
<tr class="r2">
<td class="c8" rowspan="6">16 级 刑 事 技 术 班 </td>
<td class="c9" rowspan="2">课程</td>
<td class="c10" rowspan="2">刑法</td>
<td class="c10" rowspan="6">自习</td>
<td class="c11">刑事图像</td>
<td class="c12" rowspan="2">民 法(选修)</td>
<td class="c13">派出所工作</td>
<td class="c12" rowspan="2">刑事图像</td>
<td class="c12" rowspan="2">法医学</td>
<td class="c14" rowspan="2">派出所工作</td>
<td class="c15">法医学</td>
<td class="c12" rowspan="2">国内安全保卫</td>
<td class="c12" rowspan="2">体能</td>
<td class="c12" rowspan="6">自习</td>
<td class="c12" rowspan="2">刑事技术总论</td>
<td class="c12" rowspan="2">刑法</td>
</tr>
<tr class="r3">
<td class="c11">自习</td>
<td class="c11">自习</td>
<td class="c11">自习</td>
</tr>
<tr class="r3">
<td class="c16" rowspan="2">教师</td>
<td class="c12" rowspan="2">曾岚</td>
<td class="c15">陈磊</td>
<td class="c12" rowspan="2">邵刚</td>
<td class="c15">杨丽伟</td>
<td class="c12" rowspan="2">陈磊</td>
<td class="c12" rowspan="2">于辉</td>
<td class="c12" rowspan="2">杨丽伟</td>
<td class="c15">于辉</td>
<td class="c12" rowspan="2">朱学强</td>
<td class="c12" rowspan="2">张付海</td>
<td class="c12" rowspan="2">王 伟(刑技)</td>
<td class="c12" rowspan="2">曾岚</td>
</tr>
<tr class="r3">
<td class="c11"> </td>
<td class="c11"> </td>
<td class="c11"> </td>
</tr>
<tr class="r3">
<td class="c16" rowspan="2">教室</td>
<td class="c15" rowspan="2">206</td>
<td class="c15">206</td>
<td class="c15" rowspan="2">206</td>
<td class="c15">206</td>
<td class="c15" rowspan="2">206</td>
<td class="c15" rowspan="2">206</td>
<td class="c15" rowspan="2">206</td>
<td class="c15">206</td>
<td class="c15" rowspan="2">206</td>
<td class="c15" rowspan="2">操场</td>
<td class="c15" rowspan="2">206</td>
<td class="c15" rowspan="2">206</td>
</tr>
<tr class="r4">
<td class="c15"> </td>
<td class="c11"> </td>
<td class="c11"> </td>
</tr>
<tr class="r2">
<td class="c8" rowspan="6">16 级 刑 事 侦 查 </td>
<td class="c17" rowspan="2">课程</td>
<td class="c12" rowspan="6">自习</td>
<td class="c12" rowspan="2">侦查措施</td>
<td class="c12" rowspan="2">经济案件侦查</td>
<td class="c14" rowspan="2">公安信息化</td>
<td class="c14" rowspan="2">公安信息化</td>
<td class="c12" rowspan="2">刑法</td>
<td class="c12" rowspan="2">体能</td>
<td class="c12" rowspan="6">自习</td>
<td class="c12" rowspan="2">痕迹检验</td>
<td class="c12" rowspan="2">刑法</td>
<td class="c12" rowspan="2">国内安全保卫</td>
<td class="c18">经济案件侦查</td>
<td class="c12" rowspan="2">痕迹检验</td>
<td class="c12" rowspan="2">民 法(选修)</td>
</tr>
<tr class="r3">
<td class="c11">侦查措施</td>
</tr>
<tr class="r3">
<td class="c17" rowspan="2">教师</td>
<td class="c12" rowspan="2">徐宏涛</td>
<td class="c12" rowspan="2">张静</td>
<td class="c12" rowspan="2">赵晓松</td>
<td class="c12" rowspan="2">赵晓松</td>
<td class="c12" rowspan="2">王骏强</td>
<td class="c12" rowspan="2">张付海</td>
<td class="c12" rowspan="2">郭海川</td>
<td class="c12" rowspan="2">王骏强</td>
<td class="c12" rowspan="2">朱学强</td>
<td class="c15">张静</td>
<td class="c12" rowspan="2">郭海川</td>
<td class="c12" rowspan="2">邵刚</td>
</tr>
<tr class="r3">
<td class="c11">徐宏涛</td>
</tr>
<tr class="r3">
<td class="c17" rowspan="2">教室</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">3号机房</td>
<td class="c15" rowspan="2">3号机房</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">操场</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">202</td>
<td class="c15" rowspan="2">202</td>
</tr>
<tr class="r5">
</tr>
<tr class="r2">
<td class="c8" rowspan="6">16 级 治 安 管 理 班 </td>
<td class="c17" rowspan="2">课程</td>
<td class="c12" rowspan="2">刑事技术</td>
<td class="c12" rowspan="2">体能</td>
<td class="c12" rowspan="2">刑事技术</td>
<td class="c12" rowspan="2">治安秩序管理</td>
<td class="c12" rowspan="2">刑事侦查概论</td>
<td class="c12" rowspan="2">刑法</td>
<td class="c18">群众工作与纠纷调解</td>
<td class="c12" rowspan="2">群众工作与纠纷调解</td>
<td class="c12" rowspan="2">公共关系(选修)</td>
<td class="c12" rowspan="2">刑事侦查概论</td>
<td class="c12" rowspan="2">刑法</td>
<td class="c12" rowspan="6">自习</td>
<td class="c12" rowspan="6">自习</td>
<td class="c12" rowspan="6">自习</td>
</tr>
<tr class="r6">
<td class="c19">q</td>
</tr>
<tr class="r7">
<td class="c17" rowspan="2">教师</td>
<td class="c12" rowspan="2">郭海川 韩易浦</td>
<td class="c12" rowspan="2">张付海</td>
<td class="c12" rowspan="2">郭海川 韩易浦</td>
<td class="c12" rowspan="2">翟政亮</td>
<td class="c12" rowspan="2">邵妍</td>
<td class="c12" rowspan="2">薛强</td>
<td class="c15">刘晓鹏</td>
<td class="c12" rowspan="2">刘晓鹏</td>
<td class="c12" rowspan="2">尚欣</td>
<td class="c12" rowspan="2">邵妍</td>
<td class="c12" rowspan="2">薛强</td>
</tr>
<tr class="r7">
<td class="c11">翟政亮</td>
</tr>
<tr class="r3">
<td class="c17" rowspan="2">教室</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">操场</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
<td class="c15" rowspan="2">218</td>
</tr>
<tr class="r8">
</tr>
<tr class="r2">
<td class="c13" rowspan="6">16 网 络 安 全 监 察 1 班</td>
<td class="c17" rowspan="2">课程</td>
<td class="c12" rowspan="2">应用写作</td>
<td class="c14" rowspan="2">数据库系统应用</td>
<td class="c20" rowspan="2">周二中午:计算机安全管理及实用技术</td>
<td class="c13">刑事诉讼法</td>
<td class="c21" rowspan="2">周一中午:数据库系统应用</td>
<td class="c12" rowspan="2">民法</td>
<td class="c12" rowspan="2">体育</td>
<td class="c12" rowspan="2">VB语言程序设计</td>
<td class="c12" rowspan="6">选修</td>
<td class="c12" rowspan="2">VB语言程序设计</td>
<td class="c12" rowspan="2">刑事诉讼法</td>
<td class="c12" rowspan="6">选修</td>
<td class="c15">应用写作</td>
<td class="c12" rowspan="2">犯罪心理</td>
</tr>
<tr class="r2">
<td class="c11">民法</td>
<td class="c11">犯罪心理</td>
</tr>
<tr class="r9">
<td class="c17" rowspan="2">教师</td>
<td class="c12" rowspan="2">关利</td>
<td class="c12" rowspan="2">杨斌</td>
<td class="c12" rowspan="2">赵晓松</td>
<td class="c15">王伟</td>
<td class="c12" rowspan="2">杨斌</td>
<td class="c12" rowspan="2">李静</td>
<td class="c12" rowspan="2">程军</td>
<td class="c12" rowspan="2">赵伟</td>
<td class="c12" rowspan="2">赵伟</td>
<td class="c12" rowspan="2">王伟</td>
<td class="c15">关利</td>
<td class="c12" rowspan="2">张学林</td>
</tr>
<tr class="r10">
<td class="c11">李静</td>
<td class="c11">张学林</td>
</tr>
<tr class="r3">
<td class="c17" rowspan="2">教室</td>
<td class="c15" rowspan="2">东阶梯</td>
<td class="c15" rowspan="2">2号机房</td>
<td class="c15" rowspan="2">主楼201</td>
<td class="c15" rowspan="2">101</td>
<td class="c15" rowspan="2">2号机房</td>
<td class="c15" rowspan="2">101</td>
<td class="c15" rowspan="2">操场</td>
<td class="c15" rowspan="2">3号机房</td>
<td class="c15" rowspan="2">3号机房</td>
<td class="c15" rowspan="2">101</td>
<td class="c15">东阶梯</td>
<td class="c15" rowspan="2">主楼201</td>
</tr>
<tr class="r11">
<td class="c11">主楼201</td>
</tr>
<tr class="r12">
<td class="c22" colspan="16">注:1、课程一栏中有两科次的上面的课程单周上课下面的课程双周上课。2、每天上课时间上午第1节8:30至9:55第2节10:15至11:40中午上课时间12:30至13:55下午第3节14:00至15:25。</td>
</tr>
</tbody>
</table>
</body>
</html>