该项目停滞多时,终于在今日重启了!原来的开发模式,效率太低了。现在重启,为了提高开发效率,决定做一系列的升级改造。
引入Lombok
引入MyBatisPlus
引入Swagger
引入代码生成器
使用Java8新特性语法
......
2021年3月28日
一、引入Lombok
1、添加pom依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency>
2、实体类增加注解
@Data @NoArgsConstructor
二、引入MybatisPlus
1、添加pom依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency>
2、去除已有的mybatis依赖
3、修改实体类,增加注解
@Data @NoArgsConstructor @TableName("admin_user") @ApiModel(value = "AdminUser", description = "管理用户") public class AdminUser implements Serializable{ /** * */ private static final long serialVersionUID = 1L; /** * 主键id */ @ApiModelProperty("主键id") @NotNull(message = "主键id不能为空") @TableId(value = "id", type = IdType.AUTO) private Integer userId; /** * 用户名 */ @ApiModelProperty("用户名") @Length(max = 255, message = "用户名长度不能超过255") @TableField(value = "userName") private String userName; /** * 密码 */ @ApiModelProperty("密码") @Length(max = 255, message = "密码长度不能超过255") @TableField(value = "passWord") private String passWord; /** * 昵称 */ @ApiModelProperty("昵称") @Length(max = 255, message = "昵称长度不能超过255") @TableField(value = "nickName") private String nickName; /** * 创建时间 */ @ApiModelProperty("创建时间") @TableField("createTime") @JsonFormat(shape =JsonFormat.Shape.STRING,pattern="yyyy-MM-dd") private LocalDate createTime; /** * 更新时间 */ @ApiModelProperty("更新时间") @TableField("updateTime") @JsonFormat(shape =JsonFormat.Shape.STRING,pattern="yyyy-MM-dd") private LocalDate updateTime; /** * 用户状态 1 启用,2 禁用 */ @ApiModelProperty("用户状态 1 启用,2 禁用") @TableField("userStatus") private String userStatus; /** * 是否是超级管理员 */ @ApiModelProperty("是否是超级管理员") @TableField("superUser") private String superUser; }
4、service继承IService
public interface IAdminUserService extends IService<AdminUser>
5、serviceImpl继承ServiceImpl
public class AdminUserServiceImpl extends ServiceImpl<IAdminUserMapper, AdminUser> implements IAdminUserService
6、mapper继承BaseMapper
public interface IAdminUserMapper extends BaseMapper<AdminUser>
三、引入Swagger
1、增加pom依赖 使用其他的swaggerUI
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <exclusions> <exclusion> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> </exclusion> </exclusions> <version>2.9.2</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>1.5.21</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.6</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-bean-validators</artifactId> <version>2.9.2</version> </dependency>
2、添加如下三个文件
package com.zjh.swagger2; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.github.xiaoymin.swaggerbootstrapui.configuration.SwaggerBootstrapUIConfiguration; import com.github.xiaoymin.swaggerbootstrapui.filter.ProductionSecurityFilter; import com.github.xiaoymin.swaggerbootstrapui.filter.SecurityBasicAuthFilter; import io.swagger.models.MarkdownFiles; import lombok.extern.slf4j.Slf4j; import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * Swagger2 启动类 * 启动条件: * 1,配置文件中zxw.swagger.enabled=true * 2,配置文件中不存在:zxw.swagger.enabled 值 * */ @Configuration @ConditionalOnProperty(name = "zxw.swagger.enabled", havingValue = "true", matchIfMissing = true) @EnableSwagger2 /*@EnableSwaggerBootstrapUI*/ @Import({BeanValidatorPluginsConfiguration.class, SwaggerBootstrapUIConfiguration.class, Swagger2Configuration.ZxwSecurityConfiguration.class}) public class Swagger2Configuration implements WebMvcConfigurer { /** * 这个地方要重新注入一下资源文件,不然不会注入资源的,也没有注入requestHandlerMappping,相当于xml配置的 * <!--swagger资源配置--> * <mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/> * <mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/> * 不知道为什么,这也是spring boot的一个缺点(菜鸟觉得的) * * @param registry */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } @Slf4j public static class ZxwSecurityConfiguration { @Bean @ConditionalOnMissingBean @ConditionalOnProperty(name = "zxw.swagger.production", havingValue = "true") public ProductionSecurityFilter productionSecurityFilter(SwaggerProperties swaggerProperties) { return new ProductionSecurityFilter(swaggerProperties.getProduction()); } @Bean @ConditionalOnMissingBean @ConditionalOnProperty(name = "zxw.swagger.basic.enable", havingValue = "true") public SecurityBasicAuthFilter securityBasicAuthFilter(SwaggerProperties swaggerProperties) { SwaggerProperties.Basic basic = swaggerProperties.getBasic(); return new SecurityBasicAuthFilter(basic.getEnable(), basic.getUsername(), basic.getPassword()); } @Bean(initMethod = "init") @ConditionalOnMissingBean @ConditionalOnProperty(name = "zxw.swagger.markdown.enable", havingValue = "true") public MarkdownFiles markdownFiles(SwaggerProperties swaggerProperties) { return new MarkdownFiles(swaggerProperties.getMarkdown().getBasePath()); } } }
package com.zjh.swagger2; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import org.springframework.web.bind.annotation.RequestMethod; import com.github.xiaoymin.swaggerbootstrapui.model.OrderExtensions; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Lists; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.ResponseMessageBuilder; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.ApiKey; import springfox.documentation.service.AuthorizationScope; import springfox.documentation.service.Contact; import springfox.documentation.service.Parameter; import springfox.documentation.service.ResponseMessage; import springfox.documentation.service.SecurityReference; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; /** * swagger 包扫描配置 * @Description: */ @Import({ Swagger2Configuration.class }) @EnableConfigurationProperties(SwaggerProperties.class) public class SwaggerAutoConfiguration implements BeanFactoryAware { private static final String AUTH_KEY = "token"; @Autowired SwaggerProperties swaggerProperties; private BeanFactory beanFactory; @Bean @ConditionalOnMissingBean @ConditionalOnProperty(name = "zxw.swagger.enabled", havingValue = "true", matchIfMissing = true) public List<Docket> createRestApi() { ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; List<Docket> docketList = new LinkedList<>(); // 没有分组 if (swaggerProperties.getDocket().isEmpty()) { final Docket docket = createDocket(swaggerProperties); configurableBeanFactory.registerSingleton(swaggerProperties.getTitle(), docket); docketList.add(docket); return docketList; } // 分组创建 for (String groupName : swaggerProperties.getDocket().keySet()) { SwaggerProperties.DocketInfo docketInfo = swaggerProperties.getDocket().get(groupName); ApiInfo apiInfo = new ApiInfoBuilder() .title(docketInfo.getTitle().isEmpty() ? swaggerProperties.getTitle() : docketInfo.getTitle()) .description(docketInfo.getDescription().isEmpty() ? swaggerProperties.getDescription() : docketInfo.getDescription()) .version(docketInfo.getVersion().isEmpty() ? swaggerProperties.getVersion() : docketInfo.getVersion()) .license(docketInfo.getLicense().isEmpty() ? swaggerProperties.getLicense() : docketInfo.getLicense()) .licenseUrl(docketInfo.getLicenseUrl().isEmpty() ? swaggerProperties.getLicenseUrl() : docketInfo.getLicenseUrl()) .contact( new Contact( docketInfo.getContact().getName().isEmpty() ? swaggerProperties.getContact().getName() : docketInfo.getContact().getName(), docketInfo.getContact().getUrl().isEmpty() ? swaggerProperties.getContact().getUrl() : docketInfo.getContact().getUrl(), docketInfo.getContact().getEmail().isEmpty() ? swaggerProperties.getContact().getEmail() : docketInfo.getContact().getEmail() ) ) .termsOfServiceUrl(docketInfo.getTermsOfServiceUrl().isEmpty() ? swaggerProperties.getTermsOfServiceUrl() : docketInfo.getTermsOfServiceUrl()) .build(); // base-path处理 // 当没有配置任何path的时候,解析/** if (docketInfo.getBasePath().isEmpty()) { docketInfo.getBasePath().add("/**"); } List<Predicate<String>> basePath = new ArrayList<>(docketInfo.getBasePath().size()); for (String path : docketInfo.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path处理 List<Predicate<String>> excludePath = new ArrayList<>(docketInfo.getExcludePath().size()); for (String path : docketInfo.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } Docket docket = new Docket(DocumentationType.SWAGGER_2) .host(swaggerProperties.getHost()) .apiInfo(apiInfo) .globalOperationParameters(assemblyGlobalOperationParameters(swaggerProperties.getGlobalOperationParameters(), docketInfo.getGlobalOperationParameters())) .groupName(docketInfo.getGroup()) .select() .apis(RequestHandlerSelectors.basePackage(docketInfo.getBasePackage())) .paths( Predicates.and( Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath) ) ) .build() .securitySchemes(securitySchemes()) .securityContexts(securityContexts()) .globalResponseMessage(RequestMethod.GET, getResponseMessages()) .globalResponseMessage(RequestMethod.POST, getResponseMessages()) .globalResponseMessage(RequestMethod.PUT, getResponseMessages()) .globalResponseMessage(RequestMethod.DELETE, getResponseMessages()) .extensions(Lists.newArrayList(new OrderExtensions(swaggerProperties.getOrder()))); configurableBeanFactory.registerSingleton(groupName, docket); docketList.add(docket); } return docketList; } /** * 创建 Docket对象 * * @param swaggerProperties swagger配置 * @return Docket */ private Docket createDocket(final SwaggerProperties swaggerProperties) { //API 基础信息 ApiInfo apiInfo = new ApiInfoBuilder() .title(swaggerProperties.getTitle()) .description(swaggerProperties.getDescription()) .version(swaggerProperties.getVersion()) .license(swaggerProperties.getLicense()) .licenseUrl(swaggerProperties.getLicenseUrl()) .contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail())) .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl()) .build(); // base-path处理 // 当没有配置任何path的时候,解析/** if (swaggerProperties.getBasePath().isEmpty()) { swaggerProperties.getBasePath().add("/**"); } List<Predicate<String>> basePath = new ArrayList<>(); for (String path : swaggerProperties.getBasePath()) { basePath.add(PathSelectors.ant(path)); } // exclude-path处理 List<Predicate<String>> excludePath = new ArrayList<>(); for (String path : swaggerProperties.getExcludePath()) { excludePath.add(PathSelectors.ant(path)); } return new Docket(DocumentationType.SWAGGER_2) .host(swaggerProperties.getHost()) .apiInfo(apiInfo) .groupName(swaggerProperties.getGroup()) .globalOperationParameters( buildGlobalOperationParametersFromSwaggerProperties( swaggerProperties.getGlobalOperationParameters())) .select() .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())) .paths( Predicates.and( Predicates.not(Predicates.or(excludePath)), Predicates.or(basePath) ) ) .build() .securitySchemes(securitySchemes()) .securityContexts(securityContexts()) .globalResponseMessage(RequestMethod.GET, getResponseMessages()) .globalResponseMessage(RequestMethod.POST, getResponseMessages()) .globalResponseMessage(RequestMethod.PUT, getResponseMessages()) .globalResponseMessage(RequestMethod.DELETE, getResponseMessages()) .extensions(Lists.newArrayList(new OrderExtensions(swaggerProperties.getOrder()))) ; } protected List<ResponseMessage> getResponseMessages() { List<ResponseMessage> collect = Arrays.asList( new ResponseMessageBuilder().code(0).message("成功").build() ); return collect; } @Override public void setBeanFactory(BeanFactory beanFactory) { this.beanFactory = beanFactory; } private List<SecurityContext> securityContexts() { List<SecurityContext> contexts = new ArrayList<>(1); SecurityContext securityContext = SecurityContext.builder() .securityReferences(defaultAuth()) //.forPaths(PathSelectors.regex("^(?!auth).*$")) .build(); contexts.add(securityContext); return contexts; } private List<SecurityReference> defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; List<SecurityReference> references = new ArrayList<>(1); references.add(new SecurityReference(AUTH_KEY, authorizationScopes)); return references; } private List<ApiKey> securitySchemes() { List<ApiKey> apiKeys = new ArrayList<>(1); ApiKey apiKey = new ApiKey(AUTH_KEY, AUTH_KEY, "header"); apiKeys.add(apiKey); return apiKeys; } private List<Parameter> buildGlobalOperationParametersFromSwaggerProperties( List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters) { List<Parameter> parameters = Lists.newArrayList(); if (Objects.isNull(globalOperationParameters)) { /*parameters.add(new ParameterBuilder() .name(AUTH_KEY) .description("token令牌") .modelRef(new ModelRef("string")) .parameterType("header") .defaultValue("test") .required(false) .order(1) .build());*/ return parameters; } for (SwaggerProperties.GlobalOperationParameter globalOperationParameter : globalOperationParameters) { parameters.add(new ParameterBuilder() .name(globalOperationParameter.getName()) .description(globalOperationParameter.getDescription()) .modelRef(new ModelRef(globalOperationParameter.getModelRef())) .parameterType(globalOperationParameter.getParameterType()) .required(Boolean.parseBoolean(globalOperationParameter.getRequired())) .build()); } return parameters; } /** * 局部参数按照name覆盖局部参数 * * @param globalOperationParameters * @param docketOperationParameters * @return */ private List<Parameter> assemblyGlobalOperationParameters( List<SwaggerProperties.GlobalOperationParameter> globalOperationParameters, List<SwaggerProperties.GlobalOperationParameter> docketOperationParameters) { if (Objects.isNull(docketOperationParameters) || docketOperationParameters.isEmpty()) { return buildGlobalOperationParametersFromSwaggerProperties(globalOperationParameters); } Set<String> docketNames = docketOperationParameters.stream() .map(SwaggerProperties.GlobalOperationParameter::getName) .collect(Collectors.toSet()); List<SwaggerProperties.GlobalOperationParameter> resultOperationParameters = Lists.newArrayList(); if (Objects.nonNull(globalOperationParameters)) { for (SwaggerProperties.GlobalOperationParameter parameter : globalOperationParameters) { if (!docketNames.contains(parameter.getName())) { resultOperationParameters.add(parameter); } } } resultOperationParameters.addAll(docketOperationParameters); return buildGlobalOperationParametersFromSwaggerProperties(resultOperationParameters); } }
package com.zjh.swagger2; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.springframework.boot.context.properties.ConfigurationProperties; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; /** * swagger2 属性配置 * 必须配置 prefix ,才能有提示 * */ @Data //@RefreshScope @Component @ConfigurationProperties(prefix = "zxw.swagger") public class SwaggerProperties { /** * 是否开启swagger **/ private Boolean enabled = true; /** * 是否生产环境 */ private Boolean production = false; /** * 离线文档路径 */ private Markdown markdown = new Markdown(); /** * 访问账号密码 */ private Basic basic = new Basic(); /** * 标题 **/ private String title = "在线文档"; private String group = ""; /** * 描述 **/ private String description = "zxw 在线文档"; /** * 版本 **/ private String version = "1.0"; /** * 许可证 **/ private String license = ""; /** * 许可证URL **/ private String licenseUrl = ""; /** * 服务条款URL **/ private String termsOfServiceUrl = ""; private Contact contact = new Contact(); /** * swagger会解析的包路径 **/ private String basePackage = "com.zjh"; /** * swagger会解析的url规则 **/ private List<String> basePath = new ArrayList<>(); /** * 在basePath基础上需要排除的url规则 **/ private List<String> excludePath = new ArrayList<>(); /** * 分组文档 **/ private Map<String, DocketInfo> docket = new LinkedHashMap<>(); /** * host信息 **/ private String host = ""; /** * 排序 */ private Integer order = 1; /** * 全局参数配置 **/ private List<GlobalOperationParameter> globalOperationParameters; @Setter @Getter public static class GlobalOperationParameter { /** * 参数名 **/ private String name; /** * 描述信息 **/ private String description; /** * 指定参数类型 **/ private String modelRef; /** * 参数放在哪个地方:header,query,path,body.form **/ private String parameterType; /** * 参数是否必须传 **/ private String required; } @Data public static class DocketInfo { /** * 标题 **/ private String title = "在线文档"; /** * 自定义组名 */ private String group = ""; /** * 描述 **/ private String description = "zxw 在线文档"; /** * 版本 **/ private String version = "1.0"; /** * 许可证 **/ private String license = ""; /** * 许可证URL **/ private String licenseUrl = ""; /** * 服务条款URL **/ private String termsOfServiceUrl = ""; private Contact contact = new Contact(); /** * swagger会解析的包路径 **/ private String basePackage = ""; /** * swagger会解析的url规则 **/ private List<String> basePath = new ArrayList<>(); /** * 在basePath基础上需要排除的url规则 **/ private List<String> excludePath = new ArrayList<>(); private List<GlobalOperationParameter> globalOperationParameters; /** * 排序 */ private Integer order = 1; public String getGroup() { if (group == null || "".equals(group)) { return title; } return group; } } public String getGroup() { if (group == null || "".equals(group)) { return title; } return group; } @Data public static class Contact { /** * 联系人 **/ private String name = "zxw"; /** * 联系人url **/ private String url = ""; /** * 联系人email **/ private String email = ""; } @Data @AllArgsConstructor @NoArgsConstructor public static class Basic { private Boolean enable = false; private String username = "zxw"; private String password = "zxw"; } @Data @AllArgsConstructor @NoArgsConstructor public static class Markdown { private Boolean enable = false; private String basePath = "classpath:markdown/*"; } }
3、在mvcConfigurer中添加配置
4、界面效果
关于在配置swagger过程中碰到的问题,例如此类问题
我在过程中也碰到了doc.html打不开的问题,根据当前项目环境,过滤器中排除了doc.html请求,也在mvcConfigeurer中增加了resourceHandler,结果doc.html能打开了,但是接口内容并没有显示出来。直到最后,偶然间的尝试,成功显示了接口内容。那就是在启动类注解中,指定了扫描包范围,@SpringBootApplication(scanBasePackages = {"com.zjh"}),我猜测应该是没有配置时不会扫描进去,所以404找不到资源。还是怪自己,配置不够熟悉。
时间不早了,今天就先到这里,明天再继续后面的改造。
2021.03.29更新
今天继续做服务升级,原本的mybatisPlus还未完全集成好,在使用原有语句查询时,竟然报错提示
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):com.****
而直接使用mybatisPlus的条件构造器查询就正常显示,所以mybatisPlus的配置基本是没有问题的,问题可能就出在mapper.xml的配置上了。
直到后来才发现,可能是由于mapper-location配置引起的。
本工程引入的是
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency>
配置文件中如下
#mybatis sqlMap的xml文件目录 #mybatis.mapper-locations=classpath*:sqlmap/*.xml
经过查阅:
如果引用mybatis-plus-boot-starter 依赖,需要配置 mybatis-plus.mapper-locations
如果引用mybatis-plus 依赖,需要配置 mybatis.mapper-locations
所以,修改了配置如下
mybatis-plus.mapper-locations=classpath*:sqlmap/*.xml
这样,就能正常执行了。
另外,还解决了一个@JsonFormat(shape =JsonFormat.Shape.STRING,pattern="yyyy-MM-dd")注解,页面未格式化的问题
1、pom.xml需要引入依赖
<!-- jdk8 Time--> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-parameter-names</artifactId> <version>2.9.8</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
2、后台请求原本是使用net.sf.json的方法,转换对象为json字符串,再前端解析的方式。其中将Date类型的进行了Json格式化
JsonConfig config = new JsonConfig (); config.registerJsonValueProcessor (Date.class, new JsonDateValueProcessor ("yyyy-MM-dd")); String resultStr=JSONObject.fromObject (resultMap,config).toString(); retrun resultStr;
而现在将原来的java.util.Date更改为了java.time.LocalDate,虽然加上了@JsonFormat注解,但是界面显示的还是一个[Object]。
经过断点调试,发现实际已经生效了的。但是再通过JSONObject的转换,又成功将其转换成了普通的JSON对象,LocalDate对应的是一个LocalDate的JSON格式对象而不是一个字符串。后来直接在接口返回Map,界面显示正常了。
今天用来做事的时间不多,处理完这两个问题,已经是凌晨00:29了,那么代码生成器部分就有时间再做吧。
2021.03.30更新
今天继续研究,目标是搞定代码生成器
官网其实是有教程说明的,按照此步骤操作即可。为了节省时间,以及使用顺手,参考了公司代码生成模块,基于自身项目风格做了改造。
总体来说,服务升级算是差不多了,使用JAVA8新特性编写代码就在后续过程中慢慢应用。过段时间,有空的话,研究下jenkins自动化部署,在服务器上安装一套。接下来,就可以好好写代码了。
发表评论