Commit ff7279cf authored by 月兔回旋于空中's avatar 月兔回旋于空中

结构 >> 基本结构

parent 223b33e8
Pipeline #11182 failed with stages
in 2 minutes and 44 seconds
package moe.mycard.tabulator.api;
public class ApiEnum {
public static final String api = "/api";
}
package moe.mycard.tabulator.api;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import moe.mycard.tabulator.model.dto.GlobalAskBody;
import moe.mycard.tabulator.model.dto.ReturnMessage;
import moe.mycard.tabulator.model.po.TournamentPO;
import moe.mycard.tabulator.model.vo.req.SaveTournamentReq;
import moe.mycard.tabulator.model.vo.req.UpdateTournamentReq;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@Api(tags = "首页页面接口")
@RequestMapping(IndexApi.api)
public interface IndexApi {
String api = ApiEnum.api + "/index";
@ApiOperation("新增 - 创建新的比赛")
@PostMapping("/save_tournament")
ReturnMessage<Void> save_tournament(@RequestBody GlobalAskBody<SaveTournamentReq> body);
@ApiOperation("分页 - 获取比赛列表")
@PostMapping("/page_tournament")
ReturnMessage<Page<TournamentPO>> page_tournament(@RequestBody GlobalAskBody<?> body);
@ApiOperation("编辑 - 单场次比赛信息")
@PostMapping("/edit_tournament")
ReturnMessage<Void> edit_tournament(@RequestBody GlobalAskBody<UpdateTournamentReq> body);
@ApiOperation("删除 - 单场次比赛")
@PostMapping("/delete_tournament")
ReturnMessage<Void> delete_tournament(@RequestBody GlobalAskBody<Integer> body);
@ApiOperation("详情 - 单场次比赛信息")
@PostMapping("/details_tournament_info")
ReturnMessage<Void> details_tournament_info(@RequestBody GlobalAskBody<Integer> body);
@ApiOperation("导出比赛")
@PostMapping("/export_tournament")
ReturnMessage<Void> export_tournament(@RequestBody GlobalAskBody<Integer> body);
@ApiOperation("比赛授权")
@PostMapping("/authorize")
ReturnMessage<Void> authorize(@RequestBody GlobalAskBody<?> body);
}
package moe.mycard.tabulator.api;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import moe.mycard.tabulator.model.dto.GlobalAskBody;
import moe.mycard.tabulator.model.dto.ReturnMessage;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@Api(tags = "比赛相关接口")
@RequestMapping(TournamentApi.api)
public interface TournamentApi {
String api = ApiEnum.api + "/tournament";
@ApiOperation("编辑 - 单场次比赛信息")
@PostMapping("/edit_tournament")
ReturnMessage<Void> edit_tournament(@RequestBody GlobalAskBody<?> body);
@ApiOperation("详情 - 单场次比赛信息 常规信息")
@PostMapping("/details_tournament_info")
ReturnMessage<Void> details_tournament_info(@RequestBody GlobalAskBody<Long> body);
@ApiOperation("详情 - 单场次比赛信息 树形对战信息")
@PostMapping("/details_tournament_tree")
ReturnMessage<Void> details_tournament_tree(@RequestBody GlobalAskBody<Long> body);
@ApiOperation("编辑 - 对局信息")
@PostMapping("/edit_match")
ReturnMessage<Void> edit_match(@RequestBody GlobalAskBody<?> body);
@ApiOperation("编辑 - 座位信息")
@PostMapping("/edit_seat")
ReturnMessage<Void> edit_seat(@RequestBody GlobalAskBody<?> body);
@ApiOperation("分页 - 参赛者对战记录")
@PostMapping("/page_match_record")
ReturnMessage<Page<?>> page_participant_record(@RequestBody GlobalAskBody<?> body);
@ApiOperation("导出比赛")
@PostMapping("/export_tournament")
ReturnMessage<Void> export_tournament(@RequestBody GlobalAskBody<Long> body);
@ApiOperation("导出比赛 - 单轮次")
@PostMapping("/export_round")
ReturnMessage<Void> export_round(@RequestBody GlobalAskBody<?> body);
@ApiOperation("导入比赛 - 单轮次")
@PostMapping("/import_round")
ReturnMessage<Void> import_round(@RequestBody GlobalAskBody<?> body);
}
package moe.mycard.tabulator.common;
import moe.mycard.tabulator.exception.CavCore;
import moe.mycard.tabulator.exception.CavException;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class LoginInterceptor implements HandlerInterceptor {
private final CavCore c = CavCore.getC();
// 这个方法是在访问接口之前执行的,我们只需要在这里写验证登陆状态的业务逻辑,就可以在用户调用指定接口之前验证登陆状态了
public boolean preHandle(
HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
String test = request.getHeader("Authentication");
boolean auth = test != null;
if (!auth) {
throw CavException.cast(301, "无权访问");
}
return auth;
}
}
package moe.mycard.tabulator.common;
public class UserInfo {
private static Integer userId;
public static Integer getUserId() {
if (userId == null) {
userId = 1;
}
return userId;
}
}
package moe.mycard.tabulator.common;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
/**
* 在springboot2.0.0之后,WebMvcConfigurerAdapter已经过时了 会使用WebMvcConfigurer或者WebMvcConfigurationSupport替代
*
* @author wyj
* @create 2019-06-01 21:48
*/
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurationSupport {
/**
* 在springboot2.0.0之前继承WebMvcConfigurerAdapter类,重写addInterceptors方法
*
* @param registry
*/
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// /**
// * 拦截器按照顺序执行,如果不同拦截器拦截存在相同的URL,前面的拦截器会执行,后面的拦截器将不执行
// */
// registry.addInterceptor(new AuthorityInterceptor())
// .addPathPatterns("/user/**");
// super.addInterceptors(registry);
// }
/**
* 在springboot2.0.0之后实现WebMvcConfigurer接口,重写addInterceptors方法
*
* @param registry
*/
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// /**
// * 拦截器按照顺序执行,如果不同拦截器拦截存在相同的URL,前面的拦截器会执行,后面的拦截器将不执行
// */
// registry.addInterceptor(new AuthorityInterceptor())
// .addPathPatterns("/user/**");
// }
/**
* 在springboot2.0.0之后继承WebMvcConfigurationSupport类,重写addInterceptors方法
*
* @param registry
*/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
/** 拦截器按照顺序执行,如果不同拦截器拦截存在相同的URL,前面的拦截器会执行,后面的拦截器将不执行 */
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
package moe.mycard.tabulator.controllers;
import moe.mycard.tabulator.model.dto.PageSettings;
import moe.mycard.tabulator.model.dto.PaginatedReturnMessage;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping(value = "/api")
public class AppController {
@GetMapping(value = "/test")
public PaginatedReturnMessage<String> get(PageSettings settings) {
List<String> result = new ArrayList<>();
result.add("Nanahira");
result.add("Momobako");
return new PaginatedReturnMessage<String>(200, "success", result, 2, settings);
}
}
package moe.mycard.tabulator.controllers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.val;
import moe.mycard.tabulator.api.IndexApi;
import moe.mycard.tabulator.model.dto.GlobalAskBody;
import moe.mycard.tabulator.model.dto.ReturnMessage;
import moe.mycard.tabulator.model.po.TournamentPO;
import moe.mycard.tabulator.model.service.ds.IndexService;
import moe.mycard.tabulator.model.vo.req.SaveTournamentReq;
import moe.mycard.tabulator.model.vo.req.UpdateTournamentReq;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class IndexDo implements IndexApi {
@Resource private IndexService indexService;
@Override
public ReturnMessage<Void> save_tournament(GlobalAskBody<SaveTournamentReq> body) {
indexService.saveTournament(body);
return ReturnMessage.ok();
}
@Override
public ReturnMessage<Page<TournamentPO>> page_tournament(GlobalAskBody<?> body) {
val page = indexService.pageTournament(body);
return ReturnMessage.data(page);
}
@Override
public ReturnMessage<Void> edit_tournament(GlobalAskBody<UpdateTournamentReq> body) {
indexService.editTournament(body);
return ReturnMessage.ok();
}
@Override
public ReturnMessage<Void> delete_tournament(GlobalAskBody<Integer> body) {
indexService.deleteTournament(body);
return ReturnMessage.ok();
}
@Override
public ReturnMessage<Void> details_tournament_info(GlobalAskBody<Integer> body) {
return null;
}
@Override
public ReturnMessage<Void> export_tournament(GlobalAskBody<Integer> body) {
return null;
}
@Override
public ReturnMessage<Void> authorize(GlobalAskBody<?> body) {
return null;
}
}
package moe.mycard.tabulator.controllers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import moe.mycard.tabulator.api.TournamentApi;
import moe.mycard.tabulator.model.dto.GlobalAskBody;
import moe.mycard.tabulator.model.dto.ReturnMessage;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TournamentDo implements TournamentApi {
@Override
public ReturnMessage<Void> edit_tournament(GlobalAskBody<?> body) {
return null;
}
@Override
public ReturnMessage<Void> details_tournament_info(GlobalAskBody<Long> body) {
return null;
}
@Override
public ReturnMessage<Void> details_tournament_tree(GlobalAskBody<Long> body) {
return null;
}
@Override
public ReturnMessage<Void> edit_match(GlobalAskBody<?> body) {
return null;
}
@Override
public ReturnMessage<Void> edit_seat(GlobalAskBody<?> body) {
return null;
}
@Override
public ReturnMessage<Page<?>> page_participant_record(GlobalAskBody<?> body) {
return null;
}
@Override
public ReturnMessage<Void> export_tournament(GlobalAskBody<Long> body) {
return null;
}
@Override
public ReturnMessage<Void> export_round(GlobalAskBody<?> body) {
return null;
}
@Override
public ReturnMessage<Void> import_round(GlobalAskBody<?> body) {
return null;
}
}
package moe.mycard.tabulator.exception;
import moe.mycard.tabulator.model.dto.GlobalAskBody;
/** 异常检查器 */
public class CavCore {
/** 单例c */
private static volatile CavCore c;
/**
* 直接获取检查器
*
* @return ParameterCheck = new ParameterCheck()
*/
public static CavCore getC() {
if (c == null) {
synchronized (CavCore.class) {
if (c == null) {
c = new CavCore();
}
}
}
return c;
}
/**
* 错误校验
*
* @throws CavException 参数校验异常,携带输入的异常信息内容
*/
public void c(boolean isMistake, String message) throws CavException {
if (isMistake) throw CavException.cast(message);
}
/**
* 错误校验
*
* @throws CavException 参数校验异常,携带输入的异常信息内容
*/
public void ck(Object key, Object _key) throws CavException {
if (key != _key) throw CavException.cast("参数错误");
}
/**
* 错误校验 判空形(cn -> check null)
*
* @param t 实体
* @param <object> 实体类型
* @throws CavException 空异常,携带输入的异常信息
* @see #cn(Object, String)
*/
public <object> void cn(object t) throws CavException {
cn(t, "参数为空");
}
/**
* 错误校验 判空形(cn -> check null)
*
* @throws CavException 空异常,携带输入的异常信息
* @see #cn(Object, String)
*/
public void cn(GlobalAskBody<?> gbr) throws CavException {
cn(gbr, "参数为空");
cn(gbr.getParams(), "参数为空");
}
/**
* 错误校验 判空形(cn -> check null)
*
* @param t 实体
* @param message 错误信息
* @param <object> 实体类型
* @throws CavException 空异常,携带输入的异常信息
*/
public <object> void cn(object t, String message) throws CavException {
if (t == null) throw CavException.cast(message);
}
/**
* 错误校验 判非空形(cn -> check null)
*
* @param t 实体
* @param message 错误信息
* @param <object> 实体类型
* @throws CavException 空异常,携带输入的异常信息
*/
public <object> void cnn(object t, String message) throws CavException {
if (t != null) throw CavException.cast(message);
}
}
package moe.mycard.tabulator.exception;
import lombok.val;
import moe.mycard.tabulator.model.dto.ReturnMessage;
/**
* 统一异常类
*
* @author SPiCa
*/
public class CavException extends RuntimeException {
private Integer code;
/**
* 异常实现
*
* @param message 异常信息
*/
private CavException(String message) {
super(message);
}
/**
* 抛出异常接口 统一头部输出信息 headerMessage
*
* @param message 异常信息
* @return FileException 异常对象
*/
public static CavException cast(String message) {
return new CavException(message);
}
/**
* 抛出异常接口 统一头部输出信息 headerMessage
*
* @param message 异常信息
* @return FileException 异常对象
*/
public static CavException cast(Integer code, String message) {
val error = new CavException(message);
error.code = code;
return error;
}
/**
* 直接返回result内容
*
* @return 异常信息
*/
public ReturnMessage<Void> result() {
return ReturnMessage.error(code, this.getMessage());
}
}
package moe.mycard.tabulator.exception;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import moe.mycard.tabulator.model.dto.ReturnMessage;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
/**
* 全局异常处理器
*
* @author SPiCa
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionProcessor {
private static final ObjectMapper om = new ObjectMapper();
private static String key2Val(String json, String key) {
try {
JsonNode node = om.readTree(json);
if (node != null) {
return node.findValue(key).asText();
}
} catch (JsonProcessingException e) {
log.error("【log.23101】获取json节点的值错误", e);
}
return null;
}
private static String substringBetween(String str, String open, String close) {
if (str != null && open != null && close != null) {
int start = str.indexOf(open);
if (start != -1) {
int end = str.indexOf(close, start + open.length());
if (end != -1) {
return str.substring(start + open.length(), end);
}
}
}
return null;
}
/** 全局未知异常捕获 */
@ExceptionHandler(Exception.class)
public ReturnMessage<Void> exception(Exception ex, HttpServletRequest request) {
log(true, ex, request);
return ReturnMessage.error();
}
/** 请求类型错误 */
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public ReturnMessage<Void> exception(
HttpRequestMethodNotSupportedException ex, HttpServletRequest request) {
log(false, ex, request);
return ReturnMessage.error("请求类型错误,该资源不支持此请求类型");
}
/**
* 打印错误消息
*
* @param ex 异常信息
* @param request 请求对象
*/
private void log(boolean all, Exception ex, HttpServletRequest request) {
log.error(
"{}:************************ STR *******************************", all ? "未知异常" : "预知异常");
log.error("异常名称:【{}】", getMsg(ex));
log.error("请求类型:【{}】", request.getMethod());
log.error("请求地址:【{}】", request.getRequestURL());
Enumeration<String> es = request.getParameterNames();
String key;
if (es.hasMoreElements()) {
while (es.hasMoreElements()) {
key = es.nextElement();
String value = request.getParameter(key);
if ("pass".equals(key) || "adminPass".equals(key)) value = "******";
log.error("请求参数:【{}:{}】", key, value);
}
} else {
log.error("请求参数:【】");
}
if (all) {
Arrays.stream(ex.getStackTrace()).forEach(s -> log.error(s.toString()));
// 递归打印Cause
printCause(ex.getCause());
}
log.error(
"{}:************************ END *******************************", all ? "未知异常" : "预知异常");
}
/** 获取feign 异常时候被调用接口抛出的异常消息 */
private String getMsg(Exception e) {
Throwable t = e.getCause();
StringBuilder msg = new StringBuilder();
String exceptionName = "feign.FeignException";
if (t != null && exceptionName.equals(t.getClass().getName())) {
String open = "{";
String close = "}";
String json = substringBetween(t.getMessage(), open, close);
String m = key2Val(open + json + close, "message");
if (StringUtils.isNotBlank(m)) {
msg.append(m);
}
} else if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException me = (MethodArgumentNotValidException) e;
List<ObjectError> errors = me.getBindingResult().getAllErrors();
if (CollectionUtils.isNotEmpty(errors)) {
for (ObjectError oe : errors) {
if (StringUtils.isNotBlank(msg)) {
msg.append(',');
}
msg.append(oe.getDefaultMessage());
}
}
} else {
msg.append(e.getMessage());
}
return msg.toString();
}
/** 递归CauseBy */
private void printCause(Throwable cause) {
if (cause != null) {
log.error("Cause by:");
StackTraceElement[] error = cause.getStackTrace();
if (error.length > 0) {
log.error(error[0].toString());
}
printCause(cause.getCause());
}
}
/** 内置异常捕获 */
@ExceptionHandler(CavException.class)
public ReturnMessage<Void> exception(CavException ex, HttpServletRequest request) {
log(false, ex, request);
return ex.result();
}
}
package moe.mycard.tabulator.model.dto;
import lombok.Data;
@Data
public class BlankReturnMessage {
public Boolean success;
public String message;
public Integer statusCode;
public Integer code;
public BlankReturnMessage() {}
public BlankReturnMessage(Integer statusCode, String message) {
this.success = (statusCode < 300);
this.message = message;
this.statusCode = statusCode;
this.code = statusCode;
}
}
package moe.mycard.tabulator.model.dto;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Data;
/** 全局入参子类 */
@Data
public class GlobalAskBody<T> {
/** 请求参数 */
private T params;
/** 页码 */
private Integer pageNum;
/** 一页显示的数量 */
private Integer pageSize;
/**
* 构造分页
*
* @param <po> 构造对象
* @return page
*/
public <po> Page<po> buildPage() {
return new Page<>(getPageNum(), getPageSize());
}
/** 返回页码 默认1 */
public Integer getPageNum() {
if (pageNum == null || pageNum == 0) {
pageNum = 1;
}
return pageNum;
}
/** 返回一页显示的数量 默认20 */
public Integer getPageSize() {
if (pageSize == null || pageSize == 0) {
pageSize = 20;
}
return pageSize;
}
}
package moe.mycard.tabulator.model.dto;
import java.util.List;
public class PaginatedReturnMessage<T> extends ReturnMessage<List<T>> {
public Integer pageCount;
public Integer recordsPerPage;
public Integer total;
public Integer totalPages;
public PaginatedReturnMessage(Integer statusCode, String message, List<T> data, Integer total, PageSettingsWise pageSettings) {
super(statusCode, message, data);
this.total = total;
this.pageCount = pageSettings.getPageCount();
this.recordsPerPage = pageSettings.getRecordsPerPage();
this.totalPages = (int) Math.ceil((double) total / (double) recordsPerPage);
}
}
// package moe.mycard.tabulator.model.dto;
//
// import java.util.List;
//
// public class PaginatedReturnMessage<T> extends ReturnMessage<List<T>> {
// public Integer pageCount;
// public Integer recordsPerPage;
// public Integer total;
// public Integer totalPages;
// public PaginatedReturnMessage(Integer statusCode, String message, List<T> data, Integer total,
// PageSettingsWise pageSettings) {
// super(statusCode, message, data);
// this.total = total;
// this.pageCount = pageSettings.getPageCount();
// this.recordsPerPage = pageSettings.getRecordsPerPage();
// this.totalPages = (int) Math.ceil((double) total / (double) recordsPerPage);
// }
// }
package moe.mycard.tabulator.model.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
@Data
public class ReturnMessage<T> extends BlankReturnMessage {
public T data;
public ReturnMessage(Integer statusCode, String message, T data) {
super(statusCode, message);
this.data = data;
private Object data;
public static <vo> ReturnMessage<vo> ok() {
ReturnMessage<vo> result = new ReturnMessage<>();
result.setCode(100);
result.setMessage("操作成功");
return result;
}
public static <vo> ReturnMessage<vo> data(vo data) {
ReturnMessage<vo> result = new ReturnMessage<>();
result.setCode(100);
result.setMessage("操作成功");
result.setData(data);
return result;
}
public static ReturnMessage<Void> error(Integer code, String message) {
ReturnMessage<Void> result = new ReturnMessage<>();
result.setCode(code);
result.setMessage(message);
return result;
}
public static ReturnMessage<Void> error(String message) {
ReturnMessage<Void> result = new ReturnMessage<>();
result.setCode(300);
result.setMessage(message);
return result;
}
public static ReturnMessage<Void> error() {
ReturnMessage<Void> result = new ReturnMessage<>();
result.setCode(300);
result.setMessage("系统异常");
return result;
}
}
package moe.mycard.tabulator.model.dto.tournament;
import lombok.Data;
/** 对局树 */
@Data
public class RTree {
private SeatNode seatNode;
}
package moe.mycard.tabulator.model.dto.tournament;
public class SeatNode {}
package moe.mycard.tabulator.model.dto.tournament;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/** 比赛树 */
@Data
public class TTree {
@ApiModelProperty("比赛赛制【1 淘汰赛】【2 双败淘汰赛】【3 瑞士轮】")
private String tournamentSystem;
@ApiModelProperty("比赛 - 主键id")
@TableId(value = "tournament_id", type = IdType.AUTO)
private Integer tournamentId;
@ApiModelProperty("比赛 - 比赛名称")
private String tournamentName;
@ApiModelProperty("对局树集合")
private List<RTree> roundTreeList;
private String sign;
}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.ConfigPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 核心 - 配置表 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface ConfigMapper extends BaseMapper<po.ConfigPO> {
}
@Mapper
public interface ConfigMapper extends BaseMapper<ConfigPO> {}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.LogPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 主表 - 行为日志 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface LogMapper extends BaseMapper<po.LogPO> {
}
@Mapper
public interface LogMapper extends BaseMapper<LogPO> {}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.MatchPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 主表 - 对局记录表 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface MatchMapper extends BaseMapper<po.MatchPO> {
}
@Mapper
public interface MatchMapper extends BaseMapper<MatchPO> {}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.ParticipantPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 主表 - 参赛者 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface ParticipantMapper extends BaseMapper<po.ParticipantPO> {
}
@Mapper
public interface ParticipantMapper extends BaseMapper<ParticipantPO> {}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.SeatRecordPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 主表 - 座位记录表 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface SeatRecordMapper extends BaseMapper<po.SeatRecordPO> {
}
@Mapper
public interface SeatRecordMapper extends BaseMapper<SeatRecordPO> {}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.TournamentAssignPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 主表 - 比赛子表 比赛授权关联表 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface TournamentAssignMapper extends BaseMapper<po.TournamentAssignPO> {
}
@Mapper
public interface TournamentAssignMapper extends BaseMapper<TournamentAssignPO> {}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.TournamentPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 主表 - 比赛表 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface TournamentMapper extends BaseMapper<po.TournamentPO> {
}
@Mapper
public interface TournamentMapper extends BaseMapper<TournamentPO> {}
package mapper;
package moe.mycard.tabulator.model.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import moe.mycard.tabulator.model.po.UserPO;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 主表 - 用户表 Mapper 接口
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface UserMapper extends BaseMapper<po.UserPO> {
}
@Mapper
public interface UserMapper extends BaseMapper<UserPO> {}
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 核心 - 配置表
......
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 主表 - 行为日志
* </p>
*
* @author SPiCa
* @since 2022-03-23
......@@ -20,46 +19,51 @@ import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "Log对象", description = "主表 - 行为日志")
public class LogPO implements Serializable {
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = 1L;
@ApiModelProperty("日志 - 主键")
@TableId(value = "log_id", type = IdType.AUTO)
private Integer logId;
@ApiModelProperty("日志 - 内容")
private String logContent;
@ApiModelProperty("日志 - 主键")
@TableId(value = "log_id", type = IdType.AUTO)
private Integer logId;
@ApiModelProperty("时间 - 创建时间")
private LocalDateTime timeCreate;
@ApiModelProperty("日志 - 内容")
private String logContent;
public Integer getLogId() {
return logId;
}
@ApiModelProperty("时间 - 创建时间")
private LocalDateTime timeCreate;
public void setLogId(Integer logId) {
this.logId = logId;
}
public Integer getLogId() {
return logId;
}
public String getLogContent() {
return logContent;
}
public void setLogId(Integer logId) {
this.logId = logId;
}
public String getLogContent() {
return logContent;
}
public void setLogContent(String logContent) {
this.logContent = logContent;
}
public void setLogContent(String logContent) {
this.logContent = logContent;
}
public LocalDateTime getTimeCreate() {
return timeCreate;
}
public LocalDateTime getTimeCreate() {
return timeCreate;
}
public void setTimeCreate(LocalDateTime timeCreate) {
this.timeCreate = timeCreate;
}
public void setTimeCreate(LocalDateTime timeCreate) {
this.timeCreate = timeCreate;
}
@Override
public String toString() {
return "Log{" +
"logId=" + logId +
", logContent=" + logContent +
", timeCreate=" + timeCreate +
"}";
}
@Override
public String toString() {
return "Log{"
+ "logId="
+ logId
+ ", logContent="
+ logContent
+ ", timeCreate="
+ timeCreate
+ "}";
}
}
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
/**
* <p>
* 主表 - 对局记录表
......
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 主表 - 参赛者
......
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 主表 - 座位记录表
......
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 主表 - 比赛子表 比赛授权关联表
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Data
@TableName("ta_tournament_assign")
@ApiModel(value = "TournamentAssign对象", description = "主表 - 比赛子表 比赛授权关联表")
public class TournamentAssignPO implements Serializable {
......@@ -50,101 +51,6 @@ public class TournamentAssignPO implements Serializable {
@ApiModelProperty("权限 - 创建人")
private Integer authorUserId;
@ApiModelProperty("是否有效")
private Integer isValid;
public Integer getAssignId() {
return assignId;
}
public void setAssignId(Integer assignId) {
this.assignId = assignId;
}
public Integer getTournamentId() {
return tournamentId;
}
public void setTournamentId(Integer tournamentId) {
this.tournamentId = tournamentId;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public Boolean getAuthAccess() {
return authAccess;
}
public void setAuthAccess(Boolean authAccess) {
this.authAccess = authAccess;
}
public Boolean getAuthEdit() {
return authEdit;
}
public void setAuthEdit(Boolean authEdit) {
this.authEdit = authEdit;
}
public Boolean getAuthDelete() {
return authDelete;
}
public void setAuthDelete(Boolean authDelete) {
this.authDelete = authDelete;
}
public LocalDateTime getTimeLimit() {
return timeLimit;
}
public void setTimeLimit(LocalDateTime timeLimit) {
this.timeLimit = timeLimit;
}
public LocalDateTime getTimeCreate() {
return timeCreate;
}
public void setTimeCreate(LocalDateTime timeCreate) {
this.timeCreate = timeCreate;
}
public LocalDateTime getTimeUpdate() {
return timeUpdate;
}
public void setTimeUpdate(LocalDateTime timeUpdate) {
this.timeUpdate = timeUpdate;
}
public Integer getAuthorUserId() {
return authorUserId;
}
public void setAuthorUserId(Integer authorUserId) {
this.authorUserId = authorUserId;
}
public Integer getIsValid() {
return isValid;
}
public void setIsValid(Integer isValid) {
this.isValid = isValid;
}
@Override
public String toString() {
return "TournamentAssign{" +
"assignId=" + assignId +
", tournamentId=" + tournamentId +
", userId=" + userId +
", authAccess=" + authAccess +
", authEdit=" + authEdit +
", authDelete=" + authDelete +
", timeLimit=" + timeLimit +
", timeCreate=" + timeCreate +
", timeUpdate=" + timeUpdate +
", authorUserId=" + authorUserId +
", isValid=" + isValid +
"}";
}
@ApiModelProperty("是否有效")
private Boolean isValid;
}
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 主表 - 比赛表
* </p>
*
* @author SPiCa
* @since 2022-03-23
......@@ -20,123 +19,142 @@ import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "Tournament对象", description = "主表 - 比赛表")
public class TournamentPO implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty("比赛 - 主键id")
@TableId(value = "tournament_id", type = IdType.AUTO)
private Integer tournamentId;
@ApiModelProperty("比赛 - 比赛名称")
private String tournamentName;
@ApiModelProperty("比赛 - 比赛赛制【1 淘汰赛】【2 双败淘汰赛】【3 瑞士轮】")
private String tournamentSystem;
@ApiModelProperty("比赛 - 比赛时间(yyyy-mm-dd)")
private String tournamentTime;
@ApiModelProperty("比赛 - 比赛简介")
private String tournamentIntroduction;
@ApiModelProperty("比赛 - 桌次信息( JSON 格式)")
private String tournamentSeat;
@ApiModelProperty("比赛 - 比赛轮次")
private Integer tournamentRound;
@ApiModelProperty("时间 - 创建时间")
private LocalDateTime timeCreate;
@ApiModelProperty("时间 - 修改时间")
private LocalDateTime timeUpdate;
@ApiModelProperty("是否有效")
private Boolean isValid;
public Integer getTournamentId() {
return tournamentId;
}
public void setTournamentId(Integer tournamentId) {
this.tournamentId = tournamentId;
}
public String getTournamentName() {
return tournamentName;
}
public void setTournamentName(String tournamentName) {
this.tournamentName = tournamentName;
}
public String getTournamentSystem() {
return tournamentSystem;
}
public void setTournamentSystem(String tournamentSystem) {
this.tournamentSystem = tournamentSystem;
}
public String getTournamentTime() {
return tournamentTime;
}
public void setTournamentTime(String tournamentTime) {
this.tournamentTime = tournamentTime;
}
public String getTournamentIntroduction() {
return tournamentIntroduction;
}
public void setTournamentIntroduction(String tournamentIntroduction) {
this.tournamentIntroduction = tournamentIntroduction;
}
public String getTournamentSeat() {
return tournamentSeat;
}
public void setTournamentSeat(String tournamentSeat) {
this.tournamentSeat = tournamentSeat;
}
public Integer getTournamentRound() {
return tournamentRound;
}
public void setTournamentRound(Integer tournamentRound) {
this.tournamentRound = tournamentRound;
}
public LocalDateTime getTimeCreate() {
return timeCreate;
}
public void setTimeCreate(LocalDateTime timeCreate) {
this.timeCreate = timeCreate;
}
public LocalDateTime getTimeUpdate() {
return timeUpdate;
}
public void setTimeUpdate(LocalDateTime timeUpdate) {
this.timeUpdate = timeUpdate;
}
public Boolean getIsValid() {
return isValid;
}
public void setIsValid(Boolean isValid) {
this.isValid = isValid;
}
@Override
public String toString() {
return "Tournament{" +
"tournamentId=" + tournamentId +
", tournamentName=" + tournamentName +
", tournamentSystem=" + tournamentSystem +
", tournamentTime=" + tournamentTime +
", tournamentIntroduction=" + tournamentIntroduction +
", tournamentSeat=" + tournamentSeat +
", tournamentRound=" + tournamentRound +
", timeCreate=" + timeCreate +
", timeUpdate=" + timeUpdate +
", isValid=" + isValid +
"}";
}
private static final long serialVersionUID = 1L;
@ApiModelProperty("比赛 - 主键id")
@TableId(value = "tournament_id", type = IdType.AUTO)
private Integer tournamentId;
@ApiModelProperty("比赛 - 比赛名称")
private String tournamentName;
@ApiModelProperty("比赛 - 比赛赛制【1 淘汰赛】【2 双败淘汰赛】【3 瑞士轮】")
private String tournamentSystem;
@ApiModelProperty("比赛 - 比赛时间(yyyy-mm-dd)")
private String tournamentTime;
@ApiModelProperty("比赛 - 比赛简介")
private String tournamentIntroduction;
@ApiModelProperty("比赛 - 桌次信息( JSON 格式)")
private String tournamentSeat;
@ApiModelProperty("比赛 - 比赛轮次")
private Integer tournamentRound;
@ApiModelProperty("时间 - 创建时间")
private LocalDateTime timeCreate;
@ApiModelProperty("时间 - 修改时间")
private LocalDateTime timeUpdate;
@ApiModelProperty("是否有效")
private Boolean isValid;
public Integer getTournamentId() {
return tournamentId;
}
public void setTournamentId(Integer tournamentId) {
this.tournamentId = tournamentId;
}
public String getTournamentName() {
return tournamentName;
}
public void setTournamentName(String tournamentName) {
this.tournamentName = tournamentName;
}
public String getTournamentSystem() {
return tournamentSystem;
}
public void setTournamentSystem(String tournamentSystem) {
this.tournamentSystem = tournamentSystem;
}
public String getTournamentTime() {
return tournamentTime;
}
public void setTournamentTime(String tournamentTime) {
this.tournamentTime = tournamentTime;
}
public String getTournamentIntroduction() {
return tournamentIntroduction;
}
public void setTournamentIntroduction(String tournamentIntroduction) {
this.tournamentIntroduction = tournamentIntroduction;
}
public String getTournamentSeat() {
return tournamentSeat;
}
public void setTournamentSeat(String tournamentSeat) {
this.tournamentSeat = tournamentSeat;
}
public Integer getTournamentRound() {
return tournamentRound;
}
public void setTournamentRound(Integer tournamentRound) {
this.tournamentRound = tournamentRound;
}
public LocalDateTime getTimeCreate() {
return timeCreate;
}
public void setTimeCreate(LocalDateTime timeCreate) {
this.timeCreate = timeCreate;
}
public LocalDateTime getTimeUpdate() {
return timeUpdate;
}
public void setTimeUpdate(LocalDateTime timeUpdate) {
this.timeUpdate = timeUpdate;
}
public Boolean getIsValid() {
return isValid;
}
public void setIsValid(Boolean isValid) {
this.isValid = isValid;
}
@Override
public String toString() {
return "Tournament{"
+ "tournamentId="
+ tournamentId
+ ", tournamentName="
+ tournamentName
+ ", tournamentSystem="
+ tournamentSystem
+ ", tournamentTime="
+ tournamentTime
+ ", tournamentIntroduction="
+ tournamentIntroduction
+ ", tournamentSeat="
+ tournamentSeat
+ ", tournamentRound="
+ tournamentRound
+ ", timeCreate="
+ timeCreate
+ ", timeUpdate="
+ timeUpdate
+ ", isValid="
+ isValid
+ "}";
}
}
package po;
package moe.mycard.tabulator.model.po;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 主表 - 用户表
......
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.ConfigPO;
/**
* <p>
* 核心 - 配置表 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface IConfigService extends IService<po.ConfigPO> {
}
public interface IConfigService extends IService<ConfigPO> {}
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.LogPO;
/**
* <p>
* 主表 - 行为日志 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface ILogService extends IService<po.LogPO> {
public interface ILogService extends IService<LogPO> {
/**
* 创建日志
*
* @param userId 创建人
* @param content 内容
*/
void create(Integer userId, String content);
}
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.MatchPO;
/**
* <p>
* 主表 - 对局记录表 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface IMatchService extends IService<po.MatchPO> {
}
public interface IMatchService extends IService<MatchPO> {}
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.ParticipantPO;
/**
* <p>
* 主表 - 参赛者 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface IParticipantService extends IService<po.ParticipantPO> {
}
public interface IParticipantService extends IService<ParticipantPO> {}
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.SeatRecordPO;
/**
* <p>
* 主表 - 座位记录表 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface ISeatRecordService extends IService<po.SeatRecordPO> {
}
public interface ISeatRecordService extends IService<SeatRecordPO> {}
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.TournamentAssignPO;
import java.util.Set;
/**
* <p>
* 主表 - 比赛子表 比赛授权关联表 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface ITournamentAssignService extends IService<po.TournamentAssignPO> {
public interface ITournamentAssignService extends IService<TournamentAssignPO> {
/**
* 创建比赛,生成授权关系
*
* @param userId 创建者
* @param tId 比赛ID
*/
void create(Integer userId, Integer tId);
/**
* 获取我拥有的访问权限比赛ID
*
* @param userId 用户id
* @return 比赛id集合
*/
Set<Integer> getMyAccessTId(Integer userId);
}
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.TournamentPO;
/**
* <p>
* 主表 - 比赛表 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface ITournamentService extends IService<po.TournamentPO> {
}
public interface ITournamentService extends IService<TournamentPO> {}
package service;
package moe.mycard.tabulator.model.service;
import com.baomidou.mybatisplus.extension.service.IService;
import moe.mycard.tabulator.model.po.UserPO;
/**
* <p>
* 主表 - 用户表 服务类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
public interface IUserService extends IService<po.UserPO> {
}
public interface IUserService extends IService<UserPO> {}
package moe.mycard.tabulator.model.service.ds;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.val;
import moe.mycard.tabulator.common.UserInfo;
import moe.mycard.tabulator.exception.CavCore;
import moe.mycard.tabulator.model.dto.GlobalAskBody;
import moe.mycard.tabulator.model.po.TournamentAssignPO;
import moe.mycard.tabulator.model.po.TournamentPO;
import moe.mycard.tabulator.model.service.ILogService;
import moe.mycard.tabulator.model.service.ITournamentAssignService;
import moe.mycard.tabulator.model.service.ITournamentService;
import moe.mycard.tabulator.model.vo.req.SaveTournamentReq;
import moe.mycard.tabulator.model.vo.req.UpdateTournamentReq;
import moe.mycard.tabulator.tool.UtilTime;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class IndexService {
private final CavCore c = CavCore.getC();
@Resource private ITournamentService tournamentService;
@Resource private ITournamentAssignService tournamentAssignService;
@Resource private ILogService logService;
/**
* 展示首页的比赛列表
*
* @return 比赛分页列表
*/
public Page<TournamentPO> pageTournament(GlobalAskBody<?> body) {
c.cn(body);
val userId = UserInfo.getUserId();
// TODO 展示权限过滤
val authIdSet = tournamentAssignService.getMyAccessTId(userId);
val page =
tournamentService.page(
body.buildPage(),
new LambdaQueryWrapper<TournamentPO>()
.in(TournamentPO::getTournamentId, authIdSet)
.eq(TournamentPO::getIsValid, true));
return page;
}
public void saveTournament(GlobalAskBody<SaveTournamentReq> body) {
c.cn(body);
// ===== 主逻辑,生成比赛 =====
TournamentPO savePO = new TournamentPO();
BeanUtils.copyProperties(body.getParams(), savePO);
savePO.setIsValid(true);
savePO.setTimeCreate(UtilTime.getDateL());
tournamentService.save(savePO);
// ===== 主逻辑,生成比赛 =====
// ===== 生成比赛权限
tournamentAssignService.create(UserInfo.getUserId(), savePO.getTournamentId());
// ===== 生成操作日志
logService.create(UserInfo.getUserId(), "创建了比赛 " + savePO);
}
public void editTournament(GlobalAskBody<UpdateTournamentReq> body) {
c.cn(body);
val tid = body.getParams().getTournamentId();
c.cn(tid, "比赛id为空");
val userId = UserInfo.getUserId();
val auth =
tournamentAssignService.getOne(
new LambdaQueryWrapper<TournamentAssignPO>()
.select(TournamentAssignPO::getIsValid)
.eq(TournamentAssignPO::getIsValid, true)
.eq(TournamentAssignPO::getUserId, userId)
.eq(TournamentAssignPO::getTournamentId, tid)
.eq(TournamentAssignPO::getAuthEdit, true));
c.cn(auth, "无权编辑");
val updatePO = new TournamentPO();
BeanUtils.copyProperties(body.getParams(), updatePO);
updatePO.setTimeUpdate(UtilTime.getDateL());
tournamentService.updateById(updatePO);
// ===== 生成操作日志
logService.create(userId, "编辑了比赛 " + updatePO);
}
public void deleteTournament(GlobalAskBody<Integer> body) {
c.cn(body);
val tournamentId = body.getParams();
c.cn(tournamentId, "比赛id为空");
val userId = UserInfo.getUserId();
val auth =
tournamentAssignService.getOne(
new LambdaQueryWrapper<TournamentAssignPO>()
.select(TournamentAssignPO::getIsValid)
.eq(TournamentAssignPO::getIsValid, true)
.eq(TournamentAssignPO::getUserId, userId)
.eq(TournamentAssignPO::getTournamentId, tournamentId)
.eq(TournamentAssignPO::getAuthDelete, true));
c.cn(auth, "无权删除");
val deletePO = new TournamentPO();
deletePO.setTournamentId(tournamentId);
deletePO.setTimeUpdate(UtilTime.getDateL());
deletePO.setIsValid(false);
tournamentService.updateById(deletePO);
// ===== 生成操作日志
logService.create(userId, "删除了比赛 " + deletePO);
}
}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.ConfigMapper;
import service.IConfigService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import moe.mycard.tabulator.model.mapper.ConfigMapper;
import moe.mycard.tabulator.model.po.ConfigPO;
import moe.mycard.tabulator.model.service.IConfigService;
import org.springframework.stereotype.Service;
/**
* <p>
* 核心 - 配置表 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class ConfigServiceImpl extends ServiceImpl<ConfigMapper, po.ConfigPO> implements IConfigService {
}
public class ConfigServiceImpl extends ServiceImpl<ConfigMapper, ConfigPO>
implements IConfigService {}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.LogMapper;
import service.ILogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import moe.mycard.tabulator.model.mapper.LogMapper;
import moe.mycard.tabulator.model.po.LogPO;
import moe.mycard.tabulator.model.service.ILogService;
import moe.mycard.tabulator.tool.UtilTime;
import org.springframework.stereotype.Service;
/**
* <p>
* 主表 - 行为日志 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class LogServiceImpl extends ServiceImpl<LogMapper, po.LogPO> implements ILogService {
public class LogServiceImpl extends ServiceImpl<LogMapper, LogPO> implements ILogService {
@Override
public void create(Integer userId, String content) {
LogPO savePO = new LogPO();
savePO.setLogContent(userId + ". " + content);
savePO.setTimeCreate(UtilTime.getDateL());
save(savePO);
}
}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.MatchMapper;
import service.IMatchService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import moe.mycard.tabulator.model.mapper.MatchMapper;
import moe.mycard.tabulator.model.po.MatchPO;
import moe.mycard.tabulator.model.service.IMatchService;
import org.springframework.stereotype.Service;
/**
* <p>
* 主表 - 对局记录表 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class MatchServiceImpl extends ServiceImpl<MatchMapper, po.MatchPO> implements IMatchService {
}
public class MatchServiceImpl extends ServiceImpl<MatchMapper, MatchPO> implements IMatchService {}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.ParticipantMapper;
import service.IParticipantService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import moe.mycard.tabulator.model.mapper.ParticipantMapper;
import moe.mycard.tabulator.model.po.ParticipantPO;
import moe.mycard.tabulator.model.service.IParticipantService;
import org.springframework.stereotype.Service;
/**
* <p>
* 主表 - 参赛者 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class ParticipantServiceImpl extends ServiceImpl<ParticipantMapper, po.ParticipantPO> implements IParticipantService {
}
public class ParticipantServiceImpl extends ServiceImpl<ParticipantMapper, ParticipantPO>
implements IParticipantService {}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.SeatRecordMapper;
import service.ISeatRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import moe.mycard.tabulator.model.mapper.SeatRecordMapper;
import moe.mycard.tabulator.model.po.SeatRecordPO;
import moe.mycard.tabulator.model.service.ISeatRecordService;
import org.springframework.stereotype.Service;
/**
* <p>
* 主表 - 座位记录表 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class SeatRecordServiceImpl extends ServiceImpl<SeatRecordMapper, po.SeatRecordPO> implements ISeatRecordService {
}
public class SeatRecordServiceImpl extends ServiceImpl<SeatRecordMapper, SeatRecordPO>
implements ISeatRecordService {}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.TournamentAssignMapper;
import service.ITournamentAssignService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.val;
import moe.mycard.tabulator.model.mapper.TournamentAssignMapper;
import moe.mycard.tabulator.model.po.TournamentAssignPO;
import moe.mycard.tabulator.model.service.ITournamentAssignService;
import moe.mycard.tabulator.tool.UtilTime;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.Set;
/**
* <p>
* 主表 - 比赛子表 比赛授权关联表 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class TournamentAssignServiceImpl extends ServiceImpl<TournamentAssignMapper, po.TournamentAssignPO> implements ITournamentAssignService {
public class TournamentAssignServiceImpl
extends ServiceImpl<TournamentAssignMapper, TournamentAssignPO>
implements ITournamentAssignService {
@Override
public void create(Integer userId, Integer tId) {
val time = UtilTime.getDateL();
// ===== 比赛创建人权限 =====
TournamentAssignPO savePO = new TournamentAssignPO();
savePO.setTournamentId(tId);
savePO.setUserId(userId);
savePO.setAuthAccess(true);
savePO.setAuthEdit(true);
savePO.setAuthDelete(true);
savePO.setTimeLimit(null);
savePO.setTimeCreate(time);
savePO.setAuthorUserId(userId);
savePO.setIsValid(true);
save(savePO);
// ===== 比赛创建人权限 =====
}
@Override
public Set<Integer> getMyAccessTId(Integer userId) {
val list1 =
list(
new LambdaQueryWrapper<TournamentAssignPO>()
.select(TournamentAssignPO::getTournamentId)
.eq(TournamentAssignPO::getIsValid, true)
.eq(TournamentAssignPO::getUserId, userId)
.eq(TournamentAssignPO::getAuthAccess, true));
val list2 =
list(
new LambdaQueryWrapper<TournamentAssignPO>()
.select(TournamentAssignPO::getTournamentId)
.eq(TournamentAssignPO::getIsValid, true)
.eq(TournamentAssignPO::getUserId, -1)
.eq(TournamentAssignPO::getAuthAccess, true));
Set<Integer> result = new HashSet<>();
list1.forEach(po -> result.add(po.getTournamentId()));
list2.forEach(po -> result.add(po.getTournamentId()));
return result;
}
}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.TournamentMapper;
import service.ITournamentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import moe.mycard.tabulator.model.mapper.TournamentMapper;
import moe.mycard.tabulator.model.po.TournamentPO;
import moe.mycard.tabulator.model.service.ITournamentService;
import org.springframework.stereotype.Service;
/**
* <p>
* 主表 - 比赛表 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class TournamentServiceImpl extends ServiceImpl<TournamentMapper, po.TournamentPO> implements ITournamentService {
}
public class TournamentServiceImpl extends ServiceImpl<TournamentMapper, TournamentPO>
implements ITournamentService {}
package service.impl;
package moe.mycard.tabulator.model.service.impl;
import mapper.UserMapper;
import service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import moe.mycard.tabulator.model.mapper.UserMapper;
import moe.mycard.tabulator.model.po.UserPO;
import moe.mycard.tabulator.model.service.IUserService;
import org.springframework.stereotype.Service;
/**
* <p>
* 主表 - 用户表 服务实现类
* </p>
*
* @author SPiCa
* @since 2022-03-23
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, po.UserPO> implements IUserService {
}
public class UserServiceImpl extends ServiceImpl<UserMapper, UserPO> implements IUserService {}
package moe.mycard.tabulator.model.vo.req;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class SaveTournamentReq {
@ApiModelProperty("比赛 - 比赛名称")
private String tournamentName;
@ApiModelProperty("比赛 - 比赛赛制【1 淘汰赛】【2 双败淘汰赛】【3 瑞士轮】")
private String tournamentSystem;
@ApiModelProperty("比赛 - 比赛时间(yyyy-mm-dd)")
private String tournamentTime;
@ApiModelProperty("比赛 - 比赛简介")
private String tournamentIntroduction;
@ApiModelProperty("比赛 - 桌次信息( JSON 格式)")
private String tournamentSeat;
}
package moe.mycard.tabulator.model.vo.req;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class UpdateTournamentReq {
@ApiModelProperty("比赛 - 主键id")
@TableId(value = "tournament_id", type = IdType.AUTO)
private Integer tournamentId;
@ApiModelProperty("比赛 - 比赛名称")
private String tournamentName;
@ApiModelProperty("比赛 - 比赛赛制【1 淘汰赛】【2 双败淘汰赛】【3 瑞士轮】")
private String tournamentSystem;
@ApiModelProperty("比赛 - 比赛时间(yyyy-mm-dd)")
private String tournamentTime;
@ApiModelProperty("比赛 - 比赛简介")
private String tournamentIntroduction;
@ApiModelProperty("比赛 - 桌次信息( JSON 格式)")
private String tournamentSeat;
}
package moe.mycard.tabulator.tool;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
/**
* 时间工具类
*
* @author SPiCa
*/
public class UtilTime {
/**
* 获取时间
*
* @return Data 类型
*/
public static Date getDate() {
return new Date();
}
/**
* 获取时间
*
* @return long 时间戳
*/
public static long getDateLong() {
return System.currentTimeMillis();
}
/**
* 获取时间
*
* @return LocalDateTime 类型
*/
public static LocalDateTime getDateL() {
return LocalDateTime.now();
}
/**
* 获取时间字符串
*
* @return 年-月-日 时:分:秒
*/
public static String getDateStr() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis()));
}
/**
* 获取时间字符串
*
* @return 年-月-日 时:分:秒
*/
public static String getDateStr(Long l) {
Date date = new Date(l);
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
}
/**
* 获取时间字符串
*
* @return 年-月-日 时:分:秒
*/
public static String getDateStr(LocalDateTime time) {
Date date = Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
}
/**
* 获取时间字符串
*
* @return 年-月-日
*/
public static String getDateStrYmd() {
return new SimpleDateFormat("yyyy-MM-dd").format(new Date(System.currentTimeMillis()));
}
}
<?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="mapper.ConfigMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.ConfigMapper">
</mapper>
<?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="mapper.LogMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.LogMapper">
</mapper>
<?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="mapper.MatchMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.MatchMapper">
</mapper>
<?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="mapper.ParticipantMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.ParticipantMapper">
</mapper>
<?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="mapper.SeatRecordMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.SeatRecordMapper">
</mapper>
<?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="mapper.TournamentAssignMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.TournamentAssignMapper">
</mapper>
<?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="mapper.TournamentMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.TournamentMapper">
</mapper>
<?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="mapper.UserMapper">
<mapper namespace="moe.mycard.tabulator.model.mapper.UserMapper">
</mapper>
# 萌卡账号对接流程
## API
### 登陆接口
`POST https://sapi.moecube.com:444/accounts/signin`
该接口不应该前端或后端出现,仅供开发时调试使用。
#### 参数
参数使用 json 或 form 均可。
- `account`
- `password`
#### 返回数据
相关数据经过脱敏处理。标为 `_masked` 的字段为原本如此。
```json
{
"user": {
"id": 11111,
"username": "Nanahira",
"name": "Nanahira",
"email": "78877@qq.com",
"password_hash": "_masked",
"salt": "_masked",
"active": true,
"admin": true,
"avatar": "https://cdn02.moecube.com:444/avatars/6bfb04a0-67e4-11ec-832c-dbe2719d31fa.png",
"locale": "zh-CN",
"registration_ip_address": "_masked",
"ip_address": "_masked",
"created_at": "2018-01-01T04:03:41.000Z",
"updated_at": "2021-12-28T13:45:30.732Z"
},
"token": "<很长一大串>"
}
```
> = 400 的返回数据为失败,结果为
```json
{
"message": "Authentication Error"
}
```
### 用户验证
`GET https://sapi.moecube.com:444/accounts/authUser`
前端应该使用该接口验证 token 时效性,而后端也应该使用该接口验证用户 token 是否合法,以及获取相关的用户信息。
#### 参数
使用 Header 为 `Authorization: Bearer <token>`
#### 返回数据
200 以外返回数据为 token 无效,例如
```json
{
"message": "Authentication Error"
}
```
该 message 应该直接呈现给前端。若为 401 则后端原样返回 401 给前端。前端收到 401 应立即给予用户需要登陆的提示,并跳转到登陆页面。
200 成功返回数据:
```json
{
"id": 11111,
"username": "Nanahira",
"name": "Nanahira",
"email": "78877@qq.com",
"password_hash": "_masked",
"salt": "_masked",
"active": true,
"admin": true,
"avatar": "https://cdn02.moecube.com:444/avatars/6bfb04a0-67e4-11ec-832c-dbe2719d31fa.png",
"locale": "zh-CN",
"registration_ip_address": "_masked",
"ip_address": "_masked",
"created_at": "2018-01-01T04:03:41.000Z",
"updated_at": "2021-12-28T13:45:30.732Z"
}
```
## SSO
下列逻辑为萌卡登陆页面的相关逻辑。
### 进入登陆页面
`GET https://accounts.moecube.com/signin?sso=`
#### `sso` 参数构造方式
下列例子为 TypeScript 语法。JavaScript 用户把相关类型删除即可。
```ts
function loginUrl(callbackUrl: string) {
let params = new URLSearchParams();
params.set('return_sso_url', callbackUrl);
const payload = Buffer.from(params.toString()).toString('base64');
const url = new URL('https://accounts.moecube.com');
params = url['searchParams'];
params.set('sso', payload);
return url.toString();
}
```
### 回调处理
用户完成登陆流程后,会根据给定的回调 URL 进行跳转,并附加 sso 字段。对该 sso 字段进行 base64 解码后,可以得到下面的数据。使用 URLSearchParams 进行解析即可。
```
id=111111&username=Nanahira&name=Nanahira&email=78877%40qq.com&password_hash=_masked&salt=_masked&active=true&admin=true&avatar=https%3A%2F%2Fcdn02.moecube.com%3A444%2Favatars%2F6bfb04a0-67e4-11ec-832c-dbe2719d31fa.png&locale=zh-CN&registration_ip_address=_masked&ip_address=_masked&created_at=2018-01-01T04%3A03%3A41.000Z&updated_at=2021-12-28T13%3A45%3A30.732Z&return_sso_url=https%3A%2F%2Fwww.example.com&external_id=351863&avatar_url=https%3A%2F%2Fcdn02.moecube.com%3A444%2Favatars%2F6bfb04a0-67e4-11ec-832c-dbe2719d31fa.png&avatar_force_update=true&token=my_token
```
解码后为
```
URLSearchParams {
'id' => '111111',
'username' => 'Nanahira',
'name' => 'Nanahira',
'email' => '78877@qq.com',
'password_hash' => '_masked',
'salt' => '_masked',
'active' => 'true',
'admin' => 'true',
'avatar' => 'https://cdn02.moecube.com:444/avatars/6bfb04a0-67e4-11ec-832c-dbe2719d31fa.png',
'locale' => 'zh-CN',
'registration_ip_address' => '_masked',
'ip_address' => '_masked',
'created_at' => '2018-01-01T04:03:41.000Z',
'updated_at' => '2021-12-28T13:45:30.732Z',
'return_sso_url' => 'https://www.example.com',
'external_id' => '351863',
'avatar_url' => 'https://cdn02.moecube.com:444/avatars/6bfb04a0-67e4-11ec-832c-dbe2719d31fa.png',
'avatar_force_update' => 'true',
'token' => 'my_token'
}
```
该 token 字段即可用于后续的 API 的 `Authorization: Bearer <token>` 头部。
## 参考项目
https://code.mycard.moe/mycard/mycard-mobile/-/blob/master/src/app/login.service.ts#L13
https://code.mycard.moe/mycard/mycard-mobile/-/blob/master/src/app/auth.guard.ts#L16
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment