From bc1a716d2d100c9adf01b2138f7ea1a72f871a47 Mon Sep 17 00:00:00 2001 From: tianliyong Date: Thu, 3 Aug 2023 16:14:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 39 +++ README.md | 3 +- RELEASE.md | 2 + pom.xml | 102 +++++++ tyr-api/pom.xml | 22 ++ .../java/cn/axzo/tyr/client/TyrClient.java | 57 ++++ .../config/TyrClientAutoConfiguration.java | 28 ++ .../java/cn/axzo/tyr/client/feign/TyrApi.java | 33 +++ .../axzo/tyr/client/feign/TyrApiFallback.java | 52 ++++ .../tyr/client/feign/TyrFallbackFactory.java | 19 ++ .../cn/axzo/tyr/client/model/NewUserReq.java | 29 ++ .../axzo/tyr/client/model/QueryUserReq.java | 22 ++ .../axzo/tyr/client/model/UpdateUserReq.java | 19 ++ .../cn/axzo/tyr/client/model/UserRes.java | 21 ++ .../main/resources/META-INF/spring.factories | 2 + .../axzo/maven/archetype/client/AppTest.java | 14 + tyr-server/pom.xml | 54 ++++ .../cn/axzo/tyr/server/TyrApplication.java | 13 + .../tyr/server/common/enums/ErrorCode.java | 27 ++ .../tyr/server/common/enums/ResultCode.java | 88 ++++++ .../tyr/server/common/util/package-info.java | 1 + .../config/filter/HttpTraceLogFilter.java | 259 ++++++++++++++++++ .../filter/WrappedHttpServletRequest.java | 91 ++++++ .../axzo/tyr/server/config/package-info.java | 1 + .../tyr/server/consumer/package-info.java | 1 + .../controller/HealthCheckController.java | 22 ++ .../server/controller/app/package-info.java | 1 + .../server/controller/web/UserController.java | 76 +++++ .../server/controller/web/UserResource.java | 78 ++++++ .../cn/axzo/tyr/server/job/package-info.java | 1 + .../axzo/tyr/server/repository/UserDao.java | 55 ++++ .../repository/entity/package-info.java | 1 + .../server/repository/entity/user/User.java | 27 ++ .../server/repository/mapper/UserMapper.java | 14 + .../service/converter/EntityConverter.java | 15 + .../service/converter/UserConverter.java | 26 ++ .../service/dto/request/package-info.java | 1 + .../service/dto/request/user/NewUserDTO.java | 44 +++ .../dto/request/user/UpdateUserDTO.java | 47 ++++ .../service/dto/request/user/UserQO.java | 26 ++ .../service/dto/request/user/UserQO1.java | 26 ++ .../service/dto/response/package-info.java | 1 + .../service/dto/response/user/UserVO.java | 34 +++ .../server/service/event/package-info.java | 1 + .../server/service/manager/package-info.java | 1 + .../tyr/server/service/user/UserService.java | 29 ++ .../service/user/impl/UserServiceImpl.java | 82 ++++++ .../service/validator/package-info.java | 1 + tyr-server/src/main/resources/bootstrap.yml | 37 +++ .../src/main/resources/logback-spring.xml | 10 + .../axzo/maven/archetype/server/AppTest.java | 14 + 51 files changed, 1667 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 RELEASE.md create mode 100644 pom.xml create mode 100644 tyr-api/pom.xml create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/TyrClient.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/config/TyrClientAutoConfiguration.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApi.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApiFallback.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrFallbackFactory.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/NewUserReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/QueryUserReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/UpdateUserReq.java create mode 100644 tyr-api/src/main/java/cn/axzo/tyr/client/model/UserRes.java create mode 100644 tyr-api/src/main/resources/META-INF/spring.factories create mode 100644 tyr-api/src/test/java/cn/axzo/maven/archetype/client/AppTest.java create mode 100644 tyr-server/pom.xml create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ErrorCode.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ResultCode.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/common/util/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/HttpTraceLogFilter.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/WrappedHttpServletRequest.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/config/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/consumer/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/controller/HealthCheckController.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/controller/app/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserController.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserResource.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/job/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/UserDao.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/user/User.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/UserMapper.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/EntityConverter.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/UserConverter.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/NewUserDTO.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UpdateUserDTO.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO1.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/user/UserVO.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/event/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/manager/package-info.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/user/UserService.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/user/impl/UserServiceImpl.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/service/validator/package-info.java create mode 100644 tyr-server/src/main/resources/bootstrap.yml create mode 100644 tyr-server/src/main/resources/logback-spring.xml create mode 100644 tyr-server/src/test/java/cn/axzo/maven/archetype/server/AppTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a66b8e2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +application-local.yml +*.log + +rebel.xml +.flattened-pom.xml \ No newline at end of file diff --git a/README.md b/README.md index 5c7a0425..67fd2d26 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,2 @@ -# tyr - +# 项目介绍 权限服务 \ No newline at end of file diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000..a033ae0c --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,2 @@ +# 发布记录 + diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..4bead31e --- /dev/null +++ b/pom.xml @@ -0,0 +1,102 @@ + + + 4.0.0 + + + cn.axzo.infra + axzo-parent + 2.4.13.5 + + + cn.axzo.tyr + tyr + pom + 1.0.0-SNAPSHOT + tyr + + + tyr-server + tyr-api + + + + 2.0.0-SNAPSHOT + 2.0.0-SNAPSHOT + 1.18.22 + 1.4.2.Final + + + + + + + cn.axzo.infra + axzo-bom + ${axzo-bom.version} + pom + import + + + cn.axzo.infra + axzo-dependencies + ${axzo-dependencies.version} + pom + import + + + + + + + + + org.projectlombok + lombok + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + junit + junit + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + org.projectlombok + lombok + ${lombok.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + + + + + axzo + axzo repository + https://nexus.axzo.cn/repository/axzo/ + + + diff --git a/tyr-api/pom.xml b/tyr-api/pom.xml new file mode 100644 index 00000000..298ff057 --- /dev/null +++ b/tyr-api/pom.xml @@ -0,0 +1,22 @@ + + + 4.0.0 + + + tyr + cn.axzo.tyr + 1.0.0-SNAPSHOT + ../pom.xml + + + tyr-api + jar + tyr-api + + + + cn.axzo.framework + axzo-consumer-spring-cloud-starter + + + diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/TyrClient.java b/tyr-api/src/main/java/cn/axzo/tyr/client/TyrClient.java new file mode 100644 index 00000000..deaf693d --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/TyrClient.java @@ -0,0 +1,57 @@ +package cn.axzo.tyr.client; + +import cn.axzo.framework.domain.page.PageQO; +import cn.axzo.framework.domain.page.PageResp; +import cn.axzo.framework.domain.web.ApiException; +import cn.axzo.framework.domain.web.result.ApiPageResult; +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.feign.TyrApi; +import cn.axzo.tyr.client.model.NewUserReq; +import cn.axzo.tyr.client.model.QueryUserReq; +import cn.axzo.tyr.client.model.UpdateUserReq; +import cn.axzo.tyr.client.model.UserRes; +import cn.azxo.framework.common.model.CommonResponse; +import lombok.RequiredArgsConstructor; + +import javax.validation.Valid; + +/** + * @Author: liyong.tian + * @Date: 2022/9/17 + * @Description: + */ +@RequiredArgsConstructor +public class TyrClient { + + private final TyrApi api; + + /** + * 老项目迁移使用 + */ + public UserRes createUser(@Valid NewUserReq req) { + CommonResponse apiResult = api.createUser(req); + if (apiResult.getCode() == 200) { + return apiResult.getData(); + } + throw new RuntimeException(apiResult.getMsg()); + } + + /** + * 新项目使用 + */ + public UserRes updateUser(Long id, @Valid UpdateUserReq req) { + ApiResult apiResult = api.updateUser(id, req); + if (apiResult.isSuccess()) { + return apiResult.getData(); + } + throw new ApiException(apiResult.getRespCode()); + } + + public PageResp fetchUsers(QueryUserReq req, PageQO page) { + ApiPageResult apiPageResult = api.fetchUsers(req.toQueryMap(), page); + if (apiPageResult.isSuccess()) { + return apiPageResult.toPage(); + } + throw new ApiException(apiPageResult.getRespCode()); + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/config/TyrClientAutoConfiguration.java b/tyr-api/src/main/java/cn/axzo/tyr/client/config/TyrClientAutoConfiguration.java new file mode 100644 index 00000000..9790a2e2 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/config/TyrClientAutoConfiguration.java @@ -0,0 +1,28 @@ +package cn.axzo.tyr.client.config; + +import cn.axzo.tyr.client.TyrClient; +import cn.axzo.tyr.client.feign.TyrApi; +import cn.axzo.tyr.client.feign.TyrFallbackFactory; +import org.springframework.cloud.openfeign.EnableFeignClients; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @Author: liyong.tian + * @Date: 2022/9/17 + * @Description: + */ +@EnableFeignClients(basePackages = {"cn.axzo.tyr.client"}) +@Configuration +public class TyrClientAutoConfiguration { + + @Bean + public TyrFallbackFactory microArchetypeFallbackFactory() { + return new TyrFallbackFactory(); + } + + @Bean + public TyrClient tyrClient(TyrApi tyrApi) { + return new TyrClient(tyrApi); + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApi.java new file mode 100644 index 00000000..11e90458 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApi.java @@ -0,0 +1,33 @@ +package cn.axzo.tyr.client.feign; + +import cn.axzo.framework.domain.page.PageQO; +import cn.axzo.framework.domain.web.result.ApiPageResult; +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.NewUserReq; +import cn.axzo.tyr.client.model.UpdateUserReq; +import cn.axzo.tyr.client.model.UserRes; +import cn.azxo.framework.common.model.CommonResponse; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +/** + * @Author: liyong.tian + * @Date: 2022/9/17 + * @Description: + */ +@FeignClient(name = "tyr", url = "http://localhost:8899", fallbackFactory = TyrFallbackFactory.class) +public interface TyrApi { + + @PostMapping(value = "/api/v1/users", consumes = APPLICATION_JSON_VALUE) + CommonResponse createUser(@RequestBody NewUserReq req); + + @PutMapping(value = "/api/v2/users/{id}", consumes = APPLICATION_JSON_VALUE) + ApiResult updateUser(@PathVariable("id") Long id, @RequestBody UpdateUserReq req); + + @GetMapping(value = "/api/v2/users") + ApiPageResult fetchUsers(@RequestParam Map query, PageQO page); +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApiFallback.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApiFallback.java new file mode 100644 index 00000000..eab606a0 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrApiFallback.java @@ -0,0 +1,52 @@ +package cn.axzo.tyr.client.feign; + +import cn.axzo.framework.client.feign.FeignFallback; +import cn.axzo.framework.domain.page.PageQO; +import cn.axzo.framework.domain.web.result.ApiPageResult; +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.NewUserReq; +import cn.axzo.tyr.client.model.UpdateUserReq; +import cn.axzo.tyr.client.model.UserRes; +import cn.azxo.framework.common.model.CommonResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.Map; + +/** + * @Author: liyong.tian + * @Date: 2022/9/17 + * @Description: + */ +@Slf4j +@RequiredArgsConstructor +public class TyrApiFallback implements TyrApi { + + private final FeignFallback fallback; + + /** + * 老项目迁移使用 + * @param req + * @return + */ + @Override + public CommonResponse createUser(NewUserReq req) { + log.error("[tyr-api] createUser fallback", fallback.getCause()); + return CommonResponse.error("创建用户失败"); + } + + /** + * 新项目推荐使用 + */ + @Override + public ApiResult updateUser(Long id, UpdateUserReq req) { + log.error("[tyr-api] updateUser fallback", fallback.getCause()); + return fallback.resp(); + } + + @Override + public ApiPageResult fetchUsers(Map query, PageQO page) { + log.error("[tyr-api] fetchUsers fallback", fallback.getCause()); + return fallback.pageResp(); + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrFallbackFactory.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrFallbackFactory.java new file mode 100644 index 00000000..d15c7c57 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TyrFallbackFactory.java @@ -0,0 +1,19 @@ +package cn.axzo.tyr.client.feign; + +import cn.axzo.framework.client.feign.FeignFallback; +import cn.axzo.framework.domain.web.code.IRespCode; +import cn.axzo.framework.domain.web.code.RespCode; +import feign.hystrix.FallbackFactory; +import org.springframework.stereotype.Component; + +@Component +public class TyrFallbackFactory implements FallbackFactory { + + // TODO: 2022/11/3 100-调整为具体的项目编号,XXX-调整为项目名 + private final IRespCode respCode = new RespCode("100" + "91001", "XXX服务不可用"); + + @Override + public TyrApiFallback create(Throwable cause) { + return new TyrApiFallback(new FeignFallback(cause, respCode)); + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/NewUserReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/NewUserReq.java new file mode 100644 index 00000000..21f5c7ad --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/NewUserReq.java @@ -0,0 +1,29 @@ +package cn.axzo.tyr.client.model; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @Author: liyong.tian + * @Date: 2022/9/2 + * @Description: + */ +@Data +public class NewUserReq { + + @NotBlank(message = "名称不能为空") + private String name; + + @NotNull + private Integer sex; + + private Integer age; + + private String phone; + + private String email; + + private String address; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/QueryUserReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/QueryUserReq.java new file mode 100644 index 00000000..8d88889b --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/QueryUserReq.java @@ -0,0 +1,22 @@ +package cn.axzo.tyr.client.model; + +import cn.axzo.framework.context.client.IQueryMap; +import cn.axzo.framework.context.client.QueryMap; +import lombok.Data; + +@Data +public class QueryUserReq implements IQueryMap { + + private Long id; + + private String name; + + private String phone; + + private String email; + + @Override + public void append(QueryMap.Builder builder) { + builder.put("id", id).put("name", name).put("phone", phone).put("email", email); + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/UpdateUserReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/UpdateUserReq.java new file mode 100644 index 00000000..acb268a6 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/UpdateUserReq.java @@ -0,0 +1,19 @@ +package cn.axzo.tyr.client.model; + +import lombok.Data; + +@Data +public class UpdateUserReq { + + private String name; + + private Integer sex; + + private Integer age; + + private String phone; + + private String email; + + private String address; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/UserRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/UserRes.java new file mode 100644 index 00000000..7508a5f6 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/UserRes.java @@ -0,0 +1,21 @@ +package cn.axzo.tyr.client.model; + +import lombok.Data; + +@Data +public class UserRes { + + private Long id; + + private String name; + + private Integer sex; + + private Integer age; + + private String phone; + + private String email; + + private String address; +} diff --git a/tyr-api/src/main/resources/META-INF/spring.factories b/tyr-api/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..070ecd68 --- /dev/null +++ b/tyr-api/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +cn.axzo.micro.archetype.client.config.TyrClientAutoConfiguration \ No newline at end of file diff --git a/tyr-api/src/test/java/cn/axzo/maven/archetype/client/AppTest.java b/tyr-api/src/test/java/cn/axzo/maven/archetype/client/AppTest.java new file mode 100644 index 00000000..7d836fa0 --- /dev/null +++ b/tyr-api/src/test/java/cn/axzo/maven/archetype/client/AppTest.java @@ -0,0 +1,14 @@ +package cn.axzo.maven.archetype.client; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Unit test for simple App. + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class AppTest { + +} diff --git a/tyr-server/pom.xml b/tyr-server/pom.xml new file mode 100644 index 00000000..27a641c1 --- /dev/null +++ b/tyr-server/pom.xml @@ -0,0 +1,54 @@ + + + + tyr + cn.axzo.tyr + 1.0.0-SNAPSHOT + ../pom.xml + + 4.0.0 + + tyr-server + jar + + tyr-server + + + + cn.axzo.framework + axzo-web-spring-boot-starter + + + cn.axzo.framework + axzo-spring-cloud-starter + + + cn.axzo.framework + axzo-consumer-spring-cloud-starter + + + cn.axzo.framework + axzo-processor-spring-boot-starter + + + + cn.axzo.framework + axzo-mybatisplus-spring-boot-starter + + + + cn.axzo.framework + axzo-swagger-yapi-spring-boot-starter + + + + com.alibaba + druid-spring-boot-starter + + + + cn.axzo.framework + axzo-logger-spring-boot-starter + + + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java new file mode 100644 index 00000000..dd5073f9 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/TyrApplication.java @@ -0,0 +1,13 @@ +package cn.axzo.tyr.server; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@MapperScan(value = {"cn.axzo.**.mapper"}) +@SpringBootApplication +public class TyrApplication { + public static void main(String[] args) { + SpringApplication.run(TyrApplication.class, args); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ErrorCode.java b/tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ErrorCode.java new file mode 100644 index 00000000..7fa875f9 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ErrorCode.java @@ -0,0 +1,27 @@ +package cn.axzo.tyr.server.common.enums; + +import cn.axzo.framework.domain.web.code.IProjectRespCode; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: 响应码规范:一共8位,取值范围0~9,3位项目编号(首位不能为0)+2位模块编号+3位自定义编号 + */ +@Getter +@AllArgsConstructor +public enum ErrorCode implements IProjectRespCode { + + USER_NOT_EXISTS("01001", "用户不存在,id=%s"), + USER_PHONE_EMAIL_IS_NULL("01002", "电话和邮箱不能都为空"); + + private String code; + private String message; + + @Override + public String getProjectCode() { + // 根据不同项目进行项目编码调整,可联系框架组获取项目编号(首位不能为0) + return "100"; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ResultCode.java b/tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ResultCode.java new file mode 100644 index 00000000..e96ef1be --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/common/enums/ResultCode.java @@ -0,0 +1,88 @@ +package cn.axzo.tyr.server.common.enums; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +public enum ResultCode { + /** + * 成功 [GET] + */ + SUCCESS(200), + /** + * [POST/PUT/PATCH] 用户新建或修改数据成功 + */ + CREATED(201), + /** + * [*] 标识一个请求已经进入后台排队 (异步任务) + */ + ACCEPTED(202), + /** + * [DELETE]: 用户删除数据成功 + */ + NO_CONTENT(204), + /** + * [POST/PUT/PATCH] 用户发出的请求有错误, 服务器没有进行新建或修改数据的操作, 该操作是幂等的. + */ + FAIL(400), + /** + * [*] 标识没有权限 (令牌、用户名、密码错误) + */ + UNAUTHORIZED(401), + /** + * [*] 标识用户得到授权(与401错误相对), 但是访问是被禁止的 + */ + FORBIDDEN(403), + /** + * [*] 用户发出的请求针对的是不存在的记录, 服务器没有进行操作 + */ + NOT_FOUND(404), + /** + * [GET] 用户请求的格式不可得 (比如用户请求JSON格式, 但是只有XML格式) + */ + NOT_ACCEPTABLE(406), + /** + * [GET] 用户请求的资源被永久删除, 且不会再得到 + */ + GONE(410), + /** + * [POST/PUT/PATCH] 当创建一个对象时, 发生一个验证错误646 + */ + UNPROCESSABLE_ENTITY(422), + /** + * 服务器内部错误 + */ + INTERNAL_SERVER_ERROR(9999), + /** + * 通用业务异常 + */ + SERVICE_EXCEPTION_ERROR(9998), + + /** + * ####业务的响应码#### + * 按业务依次划分 : + * 一共6位, 第6位是业务代码 第1-5位响应码, 按业务不同码不同 + * #100000 全局级别 + */ + + /** + * 100001 当前用户被强制下线 + */ + CUSTOM_100001(100001), + /** + * 确认弹窗响应码 + */ + CUSTOM_100002(100002); + + public int code; + + ResultCode(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/package-info.java new file mode 100644 index 00000000..1cd2c6fa --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.common.util; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/HttpTraceLogFilter.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/HttpTraceLogFilter.java new file mode 100644 index 00000000..d85f107a --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/HttpTraceLogFilter.java @@ -0,0 +1,259 @@ +package cn.axzo.tyr.server.config.filter; + +import cn.azxo.framework.common.constatns.Constants; +import cn.azxo.framework.common.utils.LogUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.google.common.base.Strings; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.apache.skywalking.apm.toolkit.trace.Trace; +import org.apache.skywalking.apm.toolkit.trace.TraceContext; +import org.slf4j.MDC; +import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.util.ContentCachingRequestWrapper; +import org.springframework.web.util.ContentCachingResponseWrapper; +import org.springframework.web.util.WebUtils; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * @Author: liyong.tian + * @Date: 2022/12/6 14:48 + * @Description: Http接口日志记录 + */ +@Slf4j +@Component +public class HttpTraceLogFilter extends OncePerRequestFilter implements Ordered { + + private static final String X_REQUEST_ID = "x-request-id"; + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE - 10; + } + + @Override + @Trace(operationName = "HttpTraceLogFilter") + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + String uri = request.getRequestURI(); + String contextPath = request.getContextPath(); + String url = uri.substring(contextPath.length()); + //swagger 跳过 + if (url.contains("api-docs") || url.contains("swagger") || url.contains("checkDeath")) { + filterChain.doFilter(request, response); + return; + } + //静态资源 跳过 + if (url.contains(".")) { + filterChain.doFilter(request, response); + return; + } + if (!(request instanceof ContentCachingRequestWrapper)) { + request = new ContentCachingRequestWrapper(request); + } + if (!(response instanceof ContentCachingResponseWrapper)) { + response = new ContentCachingResponseWrapper(response); + } + + String requestId = request.getHeader(X_REQUEST_ID); + if (Strings.isNullOrEmpty(requestId)) { + MDC.put(X_REQUEST_ID, getTraceId()); + } else { + MDC.put(X_REQUEST_ID, requestId); + } + String ctxLogId = request.getHeader(Constants.CTX_LOG_ID_MDC); + if (Strings.isNullOrEmpty(ctxLogId)) { + MDC.put(Constants.CTX_LOG_ID_MDC, getTraceId()); + } else { + MDC.put(Constants.CTX_LOG_ID_MDC, ctxLogId); + } + + // 获取请求参数 + String parameter = null; + String requestContentType = request.getHeader(HttpHeaders.CONTENT_TYPE); + if (requestContentType != null) { + if (requestContentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) { + //Json + WrappedHttpServletRequest requestWrapper = new WrappedHttpServletRequest(request); + parameter = getRequestBody(requestWrapper); + request = requestWrapper; + } else if (requestContentType.startsWith(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) { + //普通表单提交 + parameter = JSON.toJSONString(request.getParameterMap()); + } else if (requestContentType.startsWith(MediaType.MULTIPART_FORM_DATA_VALUE)) { + //文件表单提交 + parameter = JSON.toJSONString("文件类型"); + } + } else if (url.startsWith("/api")) { + if ("GET".equals(request.getMethod())) { + parameter = JSON.toJSONString(request.getParameterMap()); + } else if ("POST".equals(request.getMethod())) { + WrappedHttpServletRequest requestWrapper = new WrappedHttpServletRequest(request); + parameter = getRequestBody(requestWrapper); + request = requestWrapper; + } + } else if ("GET".equals(request.getMethod())) { + parameter = JSON.toJSONString(request.getParameterMap()); + } + + long requestTime = System.currentTimeMillis(); + try { + filterChain.doFilter(request, response); + } finally { + response.setHeader(Constants.CTX_LOG_ID_MDC, MDC.get(Constants.CTX_LOG_ID_MDC)); + response.setHeader(X_REQUEST_ID, MDC.get(Constants.CTX_LOG_ID_MDC)); + + long latency = System.currentTimeMillis() - requestTime; + String responseBody = null; + int responseStatus = response.getStatus(); + String responseContentType = response.getContentType(); + //Json + if (responseContentType != null && responseContentType + .startsWith(MediaType.APPLICATION_JSON_VALUE)) { + responseBody = getResponseBody(response); + } + //记录日志 + HttpTraceLog traceLog = new HttpTraceLog(); + traceLog.setRequestContentType(requestContentType); + traceLog.setPath(url); + traceLog.setMethod(request.getMethod()); + traceLog.setTimeTaken(latency); + traceLog.setParameter(parameter); + traceLog.setResponseContentType(responseContentType); + traceLog.setStatus(responseStatus); + traceLog.setResponseBody(responseBody); + traceLog.setRequestHeaders(getRequestHeader(request)); + if (traceLog.getResponseCode() != null && traceLog.getResponseCode().equals(9999)) { + LogUtil.error(LogUtil.ErrorLevel.P0, LogUtil.ErrorType.ERROR_BUSINESS, JSON.toJSONString(traceLog)); + } else if (traceLog.getResponseCode() != null && traceLog.getResponseCode().equals(9998)) { + log.warn(JSON.toJSONString(traceLog)); + } else { + log.info(JSON.toJSONString(traceLog)); + } + updateResponse(response); + // 清理链路id + MDC.clear(); + } + } + + private String getTraceId() { + String contextTraceId = TraceContext.traceId(); + return Strings.isNullOrEmpty(contextTraceId) + ? UUID.randomUUID().toString().replaceAll("-", "") : contextTraceId; + } + + private String getRequestBody(WrappedHttpServletRequest request) throws IOException { + // 获取请求参数 + return request.getRequestParams(); + } + + @Trace(operationName = "HttpTraceLogFilter#getResponseBody") + private String getResponseBody(HttpServletResponse response) { + String responseBody = null; + ContentCachingResponseWrapper wrapper = WebUtils + .getNativeResponse(response, ContentCachingResponseWrapper.class); + if (wrapper != null) { + responseBody = new String(wrapper.getContentAsByteArray(), StandardCharsets.UTF_8); + } + return responseBody; + } + + public Map getRequestHeader(HttpServletRequest request) { + Map ret = new HashMap<>(); + Enumeration headerNames = request.getHeaderNames(); + while (headerNames.hasMoreElements()) { + String headerName = headerNames.nextElement(); + ret.put(headerName, request.getHeader(headerName)); + } + return ret; + } + + @Trace(operationName = "HttpTraceLogFilter#updateResponse") + private void updateResponse(HttpServletResponse response) throws IOException { + ContentCachingResponseWrapper responseWrapper = WebUtils + .getNativeResponse(response, ContentCachingResponseWrapper.class); + Objects.requireNonNull(responseWrapper).copyBodyToResponse(); + } + + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + private static class HttpTraceLog { + + /** + * 路径 + */ + private String path; + /** + * 参数 + */ + @JSONField(jsonDirect = true) + private String parameter; + private String requestContentType; + private String responseContentType; + private String method; + private Long timeTaken; + private Integer status; + /** + * 业务Code + */ + private Integer responseCode;//业务返回码 + /** + * 响应参数 + */ + @JSONField(jsonDirect = true) + private String responseBody; + + @JSONField(jsonDirect = true) + private Map requestHeaders; + + public String getParameter() { + if (parameter == null) { + return parameter; + } else { + return parameter.replaceAll("\n", "").replaceAll("\t", "").replaceAll("\r", ""); + } + } + + public String getResponseBody() { + if (responseBody == null) { + return responseBody; + } else { + return responseBody.replaceAll("\n", "").replaceAll("\t", "").replaceAll("\r", ""); + } + } + + public void setResponseBody(String responseBody) { + if (StringUtils.isBlank(responseBody)) { + return; + } + this.responseBody = responseBody; + JSONObject responseJson = null; + try { + responseJson = JSONObject.parseObject(responseBody); + this.responseCode = responseJson.getInteger("code"); + } catch (JSONException e) { + log.debug("ResponseBody非JSON返回", e); + } + } + } +} \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/WrappedHttpServletRequest.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/WrappedHttpServletRequest.java new file mode 100644 index 00000000..367eaf12 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/filter/WrappedHttpServletRequest.java @@ -0,0 +1,91 @@ +package cn.axzo.tyr.server.config.filter; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.apache.commons.io.IOUtils; + +/** + * @Author: liyong.tian + * @Date: 2022/12/6 14:56 + * @Description: + */ +public class WrappedHttpServletRequest extends HttpServletRequestWrapper { + + private byte[] bytes; + private WrappedServletInputStream wrappedServletInputStream; + + public WrappedHttpServletRequest(HttpServletRequest request) throws IOException { + super(request); + // 读取输入流里的请求参数,并保存到bytes里 + bytes = IOUtils.toByteArray(request.getInputStream()); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); + this.wrappedServletInputStream = new WrappedServletInputStream(byteArrayInputStream); + // 很重要,把post参数重新写入请求流 + reWriteInputStream(); + } + + /** + * 把参数重新写进请求里 + */ + public void reWriteInputStream() { + wrappedServletInputStream + .setStream(new ByteArrayInputStream(bytes != null ? bytes : new byte[0])); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + return wrappedServletInputStream; + } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(wrappedServletInputStream)); + } + + /** + * 获取post参数,可以自己再转为相应格式 + */ + public String getRequestParams() throws IOException { + return new String(bytes, this.getCharacterEncoding()); + } + + private class WrappedServletInputStream extends ServletInputStream { + + private InputStream stream; + + public WrappedServletInputStream(InputStream stream) { + this.stream = stream; + } + + public void setStream(InputStream stream) { + this.stream = stream; + } + + @Override + public int read() throws IOException { + return stream.read(); + } + + @Override + public boolean isFinished() { + return true; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + } + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/package-info.java new file mode 100644 index 00000000..8d7742d5 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.config; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/consumer/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/consumer/package-info.java new file mode 100644 index 00000000..eb001a5e --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/consumer/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.consumer; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/HealthCheckController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/HealthCheckController.java new file mode 100644 index 00000000..816ebf86 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/HealthCheckController.java @@ -0,0 +1,22 @@ +package cn.axzo.tyr.server.controller; + +import cn.axzo.framework.web.http.ApiResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @Author: liyong.tian + * @Date: 2022/11/25 18:00 + * @Description: 健康检查接口 + */ +@RestController +public class HealthCheckController { + + /** + * 探活 + */ + @GetMapping("/checkDeath") + public ApiResponse checkDeath() { + return ApiResponse.ok("ok"); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/app/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/app/package-info.java new file mode 100644 index 00000000..49e38f03 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/app/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.controller.app; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserController.java new file mode 100644 index 00000000..7ce449bd --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserController.java @@ -0,0 +1,76 @@ +package cn.axzo.tyr.server.controller.web; + +import cn.axzo.tyr.server.service.user.UserService; +import cn.axzo.tyr.server.service.dto.request.user.NewUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UpdateUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UserQO; +import cn.axzo.tyr.server.service.dto.response.user.UserVO; +import cn.azxo.framework.common.model.CommonPageResponse; +import cn.azxo.framework.common.model.CommonResponse; +import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * @Author: liyong.tian + * @Date: 2022/9/2 + * @Description: + */ +@Slf4j +@Api(tags = "web-用户信息接口") +@ApiSupport(author = "田立勇") +@RequestMapping("/api/v1") +@RestController +@RequiredArgsConstructor +public class UserController { + + private final UserService userService; + + @ApiOperation(value = "创建用户") + @PostMapping("/users") + public CommonResponse createUser(@Valid @RequestBody NewUserDTO dto) { + log.info("REST request to save user : {}", dto); + // 校验入参 + dto.valid(); + UserVO result = userService.create(dto); + return CommonResponse.success(result); + } + + @ApiOperation(value = "修改用户") + @PutMapping("/users/{id}") + public CommonResponse updateUser(@ApiParam("用户ID") @PathVariable Long id, + @Valid @RequestBody UpdateUserDTO dto) { + log.info("REST request to update user : {}", dto); + // 校验入参 + dto.valid(); + UserVO result = userService.update(id, dto); + return CommonResponse.success(result); + } + + @ApiOperation("获取用户列表") + @GetMapping("/users") + public CommonResponse> getUsers(@Valid UserQO userQO) { + CommonPageResponse results = userService.queryByPage(userQO); + return CommonResponse.success(results); + } + + @ApiOperation("获取用户详情") + @GetMapping("/users/{id}") + public CommonResponse getUser(@ApiParam("用户ID") @PathVariable Long id) { + UserVO result = userService.getOne(id); + return CommonResponse.success(result); + } + + @ApiOperation("删除用户") + @DeleteMapping("/users/{id}") + public CommonResponse deleteUser(@ApiParam("用户ID") @PathVariable Long id) { + userService.delete(id); + return CommonResponse.success(); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserResource.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserResource.java new file mode 100644 index 00000000..73607e7f --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/web/UserResource.java @@ -0,0 +1,78 @@ +package cn.axzo.tyr.server.controller.web; + +import cn.axzo.framework.domain.page.PageQO; +import cn.axzo.framework.domain.page.PageResp; +import cn.axzo.framework.web.http.ApiResponse; +import cn.axzo.framework.web.http.ApiPageResponse; +import cn.axzo.tyr.server.service.dto.request.user.NewUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UpdateUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UserQO1; +import cn.axzo.tyr.server.service.dto.response.user.UserVO; +import cn.axzo.tyr.server.service.user.UserService; +import com.github.xiaoymin.knife4j.annotations.ApiSupport; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * @Author: liyong.tian + * @Date: 2022/10/28 + * @Description: 新项目搭建推荐方式 + */ +@Slf4j +@Api(tags = "web-用户信息接口") +@ApiSupport(author = "田立勇") +@RequestMapping("/api/v2") +@RestController +@RequiredArgsConstructor +public class UserResource { + + private final UserService userService; + + @ApiOperation(value = "创建用户") + @PostMapping("/users") + public ApiResponse createUser(@Valid @RequestBody NewUserDTO dto) { + log.info("REST request to save user : {}", dto); + // 校验入参 + dto.valid(); + UserVO result = userService.create(dto); + return ApiResponse.ok(result); + } + + @ApiOperation(value = "修改用户") + @PutMapping("/users/{id}") + public ApiResponse updateUser(@ApiParam("用户ID") @PathVariable Long id, + @Valid @RequestBody UpdateUserDTO dto) { + log.info("REST request to update user : {}", dto); + // 校验入参 + dto.valid(); + UserVO result = userService.update(id, dto); + return ApiResponse.ok(result); + } + + @ApiOperation("获取用户列表") + @GetMapping("/users") + public ApiPageResponse getUsers(@ModelAttribute UserQO1 userQo, PageQO page) { + PageResp results = userService.find(userQo, page); + return ApiPageResponse.ok(results); + } + + @ApiOperation("获取用户详情") + @GetMapping("/users/{id}") + public ApiResponse getUser(@ApiParam("用户ID") @PathVariable Long id) { + UserVO result = userService.getOne(id); + return ApiResponse.ok(result); + } + + @ApiOperation("删除用户") + @DeleteMapping("/users/{id}") + public ApiResponse deleteUser(@ApiParam("用户ID") @PathVariable Long id) { + userService.delete(id); + return ApiResponse.ok(); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/job/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/job/package-info.java new file mode 100644 index 00000000..d3a347ea --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/job/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.job; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/UserDao.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/UserDao.java new file mode 100644 index 00000000..b0909277 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/UserDao.java @@ -0,0 +1,55 @@ +package cn.axzo.tyr.server.repository; + +import cn.axzo.framework.domain.page.PageQO; +import cn.axzo.tyr.server.repository.mapper.UserMapper; +import cn.axzo.tyr.server.service.dto.request.user.UserQO; +import cn.axzo.tyr.server.service.dto.request.user.UserQO1; +import cn.axzo.tyr.server.repository.entity.user.User; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Repository; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +@Repository +@RequiredArgsConstructor +public class UserDao extends ServiceImpl { + + private final UserMapper userMapper; + + public User findById(Long id) { + return userMapper.selectById(id); + } + + public void delete(Long id) { + userMapper.deleteById(id); + } + + public IPage queryByPage(UserQO userQO) { + return userMapper.selectPage(userQO.toPage(), + Wrappers.lambdaQuery(User.class) + .eq(userQO.getId() != null, User::getId, userQO.getId()) + .like(StringUtils.isNotBlank(userQO.getName()), User::getName, userQO.getName()) + .like(StringUtils.isNotBlank(userQO.getPhone()), User::getPhone, userQO.getPhone()) + .like(StringUtils.isNotBlank(userQO.getEmail()), User::getEmail, userQO.getEmail()) + .orderByDesc(User::getCreateAt) + ); + } + + public IPage find(UserQO1 userQO, PageQO page) { + return userMapper.selectPage(page.toPage(), + Wrappers.lambdaQuery(User.class) + .eq(userQO.getId() != null, User::getId, userQO.getId()) + .like(StringUtils.isNotBlank(userQO.getName()), User::getName, userQO.getName()) + .like(StringUtils.isNotBlank(userQO.getPhone()), User::getPhone, userQO.getPhone()) + .like(StringUtils.isNotBlank(userQO.getEmail()), User::getEmail, userQO.getEmail()) + .orderByDesc(User::getCreateAt) + ); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/package-info.java new file mode 100644 index 00000000..f2633475 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.repository.entity; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/user/User.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/user/User.java new file mode 100644 index 00000000..3ceee26d --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/user/User.java @@ -0,0 +1,27 @@ +package cn.axzo.tyr.server.repository.entity.user; + +import cn.axzo.framework.data.mybatisplus.model.BaseEntity; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +@Data +@TableName("b_user") +public class User extends BaseEntity { + + private String name; + + private Integer sex; + + private Integer age; + + private String phone; + + private String email; + + private String address; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/UserMapper.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/UserMapper.java new file mode 100644 index 00000000..0f0704f9 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/mapper/UserMapper.java @@ -0,0 +1,14 @@ +package cn.axzo.tyr.server.repository.mapper; + +import cn.axzo.tyr.server.repository.entity.user.User; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +@Mapper +public interface UserMapper extends BaseMapper { +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/EntityConverter.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/EntityConverter.java new file mode 100644 index 00000000..1dd728f1 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/EntityConverter.java @@ -0,0 +1,15 @@ +package cn.axzo.tyr.server.service.converter; + +import java.util.List; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +public interface EntityConverter{ + + V toVo(E var); + + List toVo(List var); +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/UserConverter.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/UserConverter.java new file mode 100644 index 00000000..af7010d8 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/converter/UserConverter.java @@ -0,0 +1,26 @@ +package cn.axzo.tyr.server.service.converter; + +import cn.axzo.tyr.server.service.dto.request.user.NewUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UpdateUserDTO; +import cn.axzo.tyr.server.service.dto.response.user.UserVO; +import cn.axzo.tyr.server.repository.entity.user.User; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; + +import static org.mapstruct.NullValueCheckStrategy.ALWAYS; + +/** + * @Author: liyong.tian + * @Date: 2022/9/2 + * @Description: + */ +@Mapper( + componentModel = "spring", + nullValueCheckStrategy = ALWAYS +) +public interface UserConverter extends EntityConverter { + + User toEntity(NewUserDTO dto); + + void updateEntity(UpdateUserDTO dto, @MappingTarget User user); +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/package-info.java new file mode 100644 index 00000000..8f23be65 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.service.dto.request; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/NewUserDTO.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/NewUserDTO.java new file mode 100644 index 00000000..732aefe6 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/NewUserDTO.java @@ -0,0 +1,44 @@ +package cn.axzo.tyr.server.service.dto.request.user; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @Author: liyong.tian + * @Date: 2022/9/2 + * @Description: + */ +@Data +public class NewUserDTO { + + @ApiModelProperty(value = "名称", position = 1) + @NotBlank(message = "名称不能为空") + private String name; + + @ApiModelProperty(value = "性别", position = 2) + @NotNull + private Integer sex; + + @ApiModelProperty(value = "年龄", position = 3) + private Integer age; + + @ApiModelProperty(value = "电话", position = 4) + private String phone; + + @ApiModelProperty(value = "邮箱", position = 5) + private String email; + + @ApiModelProperty(value = "地址", position = 6) + private String address; + + public void valid() { + // 电话和邮箱不能都为空 + if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(email)) { + throw new RuntimeException("电话和邮箱不能都为空"); + } + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UpdateUserDTO.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UpdateUserDTO.java new file mode 100644 index 00000000..bec543a7 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UpdateUserDTO.java @@ -0,0 +1,47 @@ +package cn.axzo.tyr.server.service.dto.request.user; + +import cn.axzo.framework.domain.web.ApiException; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.StringUtils; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import static cn.axzo.tyr.server.common.enums.ErrorCode.USER_PHONE_EMAIL_IS_NULL; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +@Data +public class UpdateUserDTO { + + @ApiModelProperty(value = "名称", position = 1) + @NotBlank(message = "名称不能为空") + private String name; + + @ApiModelProperty(value = "性别", position = 2) + @NotNull + private Integer sex; + + @ApiModelProperty(value = "年龄", position = 3) + private Integer age; + + @ApiModelProperty(value = "电话", position = 4) + private String phone; + + @ApiModelProperty(value = "邮箱", position = 5) + private String email; + + @ApiModelProperty(value = "地址", position = 6) + private String address; + + public void valid() { + // 电话和邮箱不能都为空 + if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(email)) { + throw new ApiException(USER_PHONE_EMAIL_IS_NULL); + } + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO.java new file mode 100644 index 00000000..090a549b --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO.java @@ -0,0 +1,26 @@ +package cn.axzo.tyr.server.service.dto.request.user; + +import cn.axzo.framework.domain.page.PageQO; +import io.swagger.annotations.ApiParam; +import lombok.Data; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +@Data +public class UserQO extends PageQO { + + @ApiParam("主键") + private Long id; + + @ApiParam("姓名") + private String name; + + @ApiParam("手机") + private String phone; + + @ApiParam("邮箱") + private String email; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO1.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO1.java new file mode 100644 index 00000000..09c4dac5 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/request/user/UserQO1.java @@ -0,0 +1,26 @@ +package cn.axzo.tyr.server.service.dto.request.user; + +import cn.axzo.framework.domain.page.PageQO; +import io.swagger.annotations.ApiParam; +import lombok.Data; + +/** + * @Author: liyong.tian + * @Date: 2022/9/5 + * @Description: + */ +@Data +public class UserQO1 { + + @ApiParam("主键") + private Long id; + + @ApiParam("姓名") + private String name; + + @ApiParam("手机") + private String phone; + + @ApiParam("邮箱") + private String email; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/package-info.java new file mode 100644 index 00000000..28c9eaaf --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.service.dto.response; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/user/UserVO.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/user/UserVO.java new file mode 100644 index 00000000..8317e4cd --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/dto/response/user/UserVO.java @@ -0,0 +1,34 @@ +package cn.axzo.tyr.server.service.dto.response.user; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Author: liyong.tian + * @Date: 2022/9/2 + * @Description: + */ +@Data +public class UserVO { + + @ApiModelProperty(value = "id", position = 1) + private Long id; + + @ApiModelProperty(value = "名称", position = 2) + private String name; + + @ApiModelProperty(value = "性别", position = 3) + private Integer sex; + + @ApiModelProperty(value = "年龄", position = 4) + private Integer age; + + @ApiModelProperty(value = "电话", position = 5) + private String phone; + + @ApiModelProperty(value = "邮箱", position = 6) + private String email; + + @ApiModelProperty(value = "地址", position = 7) + private String address; +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/event/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/event/package-info.java new file mode 100644 index 00000000..0d058404 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/event/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.service.event; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/manager/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/manager/package-info.java new file mode 100644 index 00000000..9270b83b --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/manager/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.service.manager; \ No newline at end of file diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/user/UserService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/user/UserService.java new file mode 100644 index 00000000..1cffffb4 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/user/UserService.java @@ -0,0 +1,29 @@ +package cn.axzo.tyr.server.service.user; + +import cn.axzo.framework.domain.page.PageQO; +import cn.axzo.framework.domain.page.PageResp; +import cn.axzo.tyr.server.service.dto.request.user.NewUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UpdateUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UserQO; +import cn.axzo.tyr.server.service.dto.request.user.UserQO1; +import cn.axzo.tyr.server.service.dto.response.user.UserVO; +import cn.azxo.framework.common.model.CommonPageResponse; + +/** + * @Author: liyong.tian + * @Date: 2022/9/2 + * @Description: + */ +public interface UserService { + UserVO create(NewUserDTO dto); + + UserVO update(Long id, UpdateUserDTO dto); + + UserVO getOne(Long id); + + void delete(Long id); + + CommonPageResponse queryByPage(UserQO userQO); + + PageResp find(UserQO1 userQo, PageQO page); +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/user/impl/UserServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/user/impl/UserServiceImpl.java new file mode 100644 index 00000000..56fae11d --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/user/impl/UserServiceImpl.java @@ -0,0 +1,82 @@ +package cn.axzo.tyr.server.service.user.impl; + +import cn.axzo.framework.domain.page.PageQO; +import cn.axzo.framework.domain.page.PageResp; +import cn.axzo.framework.domain.web.ApiException; +import cn.axzo.tyr.server.common.enums.ErrorCode; +import cn.axzo.tyr.server.service.dto.request.user.NewUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UpdateUserDTO; +import cn.axzo.tyr.server.service.dto.request.user.UserQO; +import cn.axzo.tyr.server.service.dto.request.user.UserQO1; +import cn.axzo.tyr.server.service.dto.response.user.UserVO; +import cn.axzo.tyr.server.repository.entity.user.User; +import cn.axzo.tyr.server.repository.UserDao; +import cn.axzo.tyr.server.service.user.UserService; +import cn.axzo.tyr.server.service.converter.UserConverter; +import cn.azxo.framework.common.model.CommonPageResponse; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @Author: liyong.tian + * @Date: 2022/9/2 + * @Description: + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements UserService { + + private final UserConverter userConverter; + + private final UserDao userDao; + + @Override + public UserVO create(NewUserDTO dto) { + User user = userConverter.toEntity(dto); + userDao.save(user); + return userConverter.toVo(user); + } + + @Override + public UserVO update(Long id, UpdateUserDTO dto) { + User user = userDao.findById(id); + if (user == null) { + throw new ApiException(ErrorCode.USER_NOT_EXISTS, id); + } + userConverter.updateEntity(dto, user); + return userConverter.toVo(user); + } + + @Override + public UserVO getOne(Long id) { + User user = userDao.findById(id); + return userConverter.toVo(user); + } + + @Override + public void delete(Long id) { + userDao.delete(id); + } + + @Override + public CommonPageResponse queryByPage(UserQO userQo) { + IPage page = userDao.queryByPage(userQo); + List userList = page.getRecords(); + if (CollectionUtils.isEmpty(userList)) { + return CommonPageResponse.zero(userQo.getPage(), userQo.getPageSize()); + } + return new CommonPageResponse<>(page.getCurrent(), page.getSize(), page.getTotal(), userConverter.toVo(page.getRecords())); + } + + @Override + public PageResp find(UserQO1 userQo, PageQO page) { + IPage userPage = userDao.find(userQo, page); + return PageResp.list(userPage, userConverter.toVo(userPage.getRecords())); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/validator/package-info.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/validator/package-info.java new file mode 100644 index 00000000..b4ae43f2 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/validator/package-info.java @@ -0,0 +1 @@ +package cn.axzo.tyr.server.service.validator; \ No newline at end of file diff --git a/tyr-server/src/main/resources/bootstrap.yml b/tyr-server/src/main/resources/bootstrap.yml new file mode 100644 index 00000000..91560edb --- /dev/null +++ b/tyr-server/src/main/resources/bootstrap.yml @@ -0,0 +1,37 @@ +spring: + application: + name: tyr + cloud: + nacos: + config: + server-addr: ${NACOS_HOST:dev-nacos.axzo.cn}:${NACOS_PORT:80} + file-extension: yaml + namespace: ${NACOS_NAMESPACE_ID:35eada10-9574-4db8-9fea-bc6a4960b6c7} + prefix: ${spring.application.name} + profiles: + active: ${NACOS_PROFILES_ACTIVE:local} + include: swagger + main: + allow-bean-definition-overriding: true + +logging: + level: + com.alibaba.nacos.client.config.impl: WARN + +management: + endpoint: + metrics: + enabled: true + prometheus: + enabled: true + endpoints: + web: + exposure: + include: "*" + metrics: + export: + prometheus: + enabled: true + +knife4j: + enable: true diff --git a/tyr-server/src/main/resources/logback-spring.xml b/tyr-server/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..922ff245 --- /dev/null +++ b/tyr-server/src/main/resources/logback-spring.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/tyr-server/src/test/java/cn/axzo/maven/archetype/server/AppTest.java b/tyr-server/src/test/java/cn/axzo/maven/archetype/server/AppTest.java new file mode 100644 index 00000000..f5b53190 --- /dev/null +++ b/tyr-server/src/test/java/cn/axzo/maven/archetype/server/AppTest.java @@ -0,0 +1,14 @@ +package cn.axzo.maven.archetype.server; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Unit test for simple App. + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class AppTest { + +}