1. Micro service module
The project is divided into these modules: public module, external API module, management and monitoring module, business module, etc.
-
For example, common modules, such as Filter, user-defined verifier, exception interceptor, paging tool class, query parameters and other commonly used modules to prevent XSS attacks in the development process.
The specific contents can be viewed by referring to the relevant codes in Ren false. The following examples are sql filtering and user-defined verification tools.
sql filtering
/** * SQL filter * @author walid */ public class SQLFilter { /** * SQL Injection filtration * @param str String to be verified */ public static String sqlInject(String str){ if(StringUtils.isBlank(str)){ return null; } //Remove the '| | | \ character str = StringUtils.replace(str, "'", ""); str = StringUtils.replace(str, "\"", ""); str = StringUtils.replace(str, ";", ""); str = StringUtils.replace(str, "\\", ""); //Convert to lowercase str = str.toLowerCase(); //Illegal character String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"}; //Judge whether illegal characters are included for(String keyword : keywords){ if(str.indexOf(keyword) != -1){ throw new RRException("Contains illegal characters"); } } return str; } }
Custom data verification
/** * @description: Custom validator * @program: youkeMall * @author: walid * @create: 2021-04-10 22:25 */ public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> { private Set<Integer> set = new HashSet<>(); /** * @description: initialization * @author: walid * @param constraintAnnotation: * @return: void * @time: 2021/4/10 22:27 */ @Override public void initialize(ListValue constraintAnnotation) { int[] vals = constraintAnnotation.vals(); for (int v : vals ) { set.add(v); } } /** * @description: Check judgment * @author: walid * @param value: * @param context: * @return: boolean * @time: 2021/4/10 22:28 */ @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { return set.contains(value); } } /** Specified check and rule **/ @Documented @Constraint(validatedBy = { ListValueConstraintValidator.class }) @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) public @interface ListValue { String message() default "{com.walid.common.valid.ListValue.message}"; Class<?>[] groups() default { }; Class<? extends Payload>[] payload() default { }; int[] vals () default { }; } # Configuration file validationmessages properties com.walid.common.valid.ListValue.message = The specified value must be filled in # Use of custom verifier /** * Display status [0-not displayed; 1-displayed] */ //Custom validator @ListValue(vals = {0,1},groups = {AddValidGroup.class}) private Integer showStatus;
2. Registration center and configuration center (nacos)
Service registration and configuration center (for dynamic management of configuration files)
pom.xml (in parent module)
<!-- Service registration/find--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- Configuration center for configuration management--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
nacos as configuration center
# bootstrap.properties # nacos service address spring.cloud.nacos.config.server-addr=127.0.0.1:8848 # nacos configuration center namespace ID spring.cloud.nacos.config.namespace=4a3fb886-b332-48bb-9675-ac302ac19145 # Configure grouping spring.cloud.nacos.config.group=dev # Specifies the first configuration of the configuration center spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml # datasouce. Grouping of YML spring.cloud.nacos.config.extension-configs[0].group=dev # Whether to dynamically refresh the configuration center spring.cloud.nacos.config.extension-configs[0].refresh=true
nacos as service registry
# bootstrap.properties spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
Open registration and discovery annotation @ EnableDiscoveryClient
/** * @description: * @author: walid * @param null: * @return: null * @time: 2021/3/8 22:31 * EnableDiscoveryClient The annotation registers the service with the nacos service center */ @EnableDiscoveryClient @SpringBootApplication public class RenrenApplication { public static void main(String[] args) { SpringApplication.run(RenrenApplication.class, args); } }
3. Remote call (feign)
use
Use openfeign to call POM XML (parent module)
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
Declare a remote call service name
@FeignClient("walid-product") public interface ProductFeignService { /** * /product/skuinfo/info/{skuId} //Address of remote call * * 1),Let all requests pass through the gateway; * 1,@FeignClient("walid-gateway"): Send a request to the machine where the Walid gateway is located * 2,/api/product/skuinfo/info/{skuId} * 2),Directly let the background specify service processing * 1,@FeignClient("walid-gateway") * 2,/product/skuinfo/info/{skuId} * * @return */ @RequestMapping("/product/skuinfo/info/{skuId}") public R info(@PathVariable("skuId") Long skuId); }
Add annotation on the service to be called
@EnableFeignClients(basePackages = "com.atguigu.gulimall.product.feign") @EnableDiscoveryClient @MapperScan("com.atguigu.gulimall.product.dao") @SpringBootApplication public class GulimallProductApplication { public static void main(String[] args) { SpringApplication.run(GulimallProductApplication.class, args); } }
Remote call
# injection @Autowired ProductFeignService productFeignService; # call R r1 = couponFeignService.saveSkuReduction(skuReductionTo); if(r1.getCode() != 0){ log.error("Remote save sku Information failure"); }
4. gateway
The gateway is used to ensure the interface specification of the previous section
pom.xml
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>
application.yml
spring: cloud: gateway: routes: # - id: test_route # uri: https://www.baidu.com # predicates: # - Query=url,baidu # # - id: qq_route # uri: https://www.qq.com # predicates: # - Query=url,qq - id: product_route uri: lb://gulimall-product predicates: - Path=/api/product/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: third_party_route uri: lb://gulimall-third-party predicates: - Path=/api/thirdparty/** filters: - RewritePath=/api/thirdparty/(?<segment>.*),/$\{segment} - id: member_route uri: lb://gulimall-member predicates: - Path=/api/member/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: ware_route uri: lb://gulimall-ware predicates: - Path=/api/ware/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: admin_route uri: lb://renren-fast predicates: - Path=/api/** filters: - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment} ## Front end project, / api ## Verification Code ## http://localhost:88/api/captcha.jpg http://localhost:8080/renren-fast/captcha.jpg ## http://localhost:88/api/product/category/list/tree ## http://localhost:10000/product/category/list/tree
Open service registration and discovery of gateway
/** * 1,Open service registration discovery * (Configure the registry address of nacos) * 2,Write gateway configuration file */ @EnableDiscoveryClient @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class GulimallGatewayApplication { public static void main(String[] args) { SpringApplication.run(GulimallGatewayApplication.class, args); } }
Configure cross domain -- extension after rule
@Configuration public class GulimallCorsConfiguration { @Bean public CorsWebFilter corsWebFilter(){ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); //1. Configure cross domain corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.setAllowCredentials(true); source.registerCorsConfiguration("/**",corsConfiguration); return new CorsWebFilter(source); } }
5. Use of mybatis plus plug-in
pom. XML (common module)
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.18</version> </dependency> <!-- Import mysql drive --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency>
Configure relevant data source information application yml
# Database connection information spring: datasource: username: password: url: jdbc:mysql://XXX. XXX. XX. 20: 3306 / [library name] driver-class-name: com.mysql.jdbc.Driver # Configure plug-in information mybatis-plus: mapper-locations: classpath:/mapper/**/*.xml global-config: db-config: id-type: auto logic-delete-value: 1 logic-not-delete-value: 0 # Configure log level logging: level: com.atguigu.gulimall: debug
There are differences in the paging plug-in information of mybatis (introduced according to the official version) https://mp.baomidou.com/guide/page.html )The old version is currently used
# MyBatisConfig @Configuration//Label configuration @EnableTransactionManagement//Open transaction @MapperScan("com.walid.youkemall.product.dao") //Scan data interface public class MyBatisConfig { // Introduce paging plug-in @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); // After setting the requested page to be larger than the maximum page, true will be called back to the home page, false will continue to request, and the default is false paginationInterceptor.setOverflow(false); // Set the maximum number of single page restrictions, 500 by default, - 1 unlimited paginationInterceptor.setLimit(500); // Turn on the join optimization of count, only for some left join s paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true)); return paginationInterceptor; } }
An entity class is displayed with lombok
@Data @TableName("pms_brand") public class BrandEntity implements Serializable { private static final long serialVersionUID = 1L; /** * Brand id */ @NotNull(message = "Brand must be specified for modification id",groups = {UpdateGroup.class}) @Null(message = "New cannot be specified id",groups = {AddGroup.class}) @TableId private Long brandId; /** * Brand name */ @NotBlank(message = "Brand name must be submitted",groups = {AddGroup.class,UpdateGroup.class}) private String name; /** * Brand logo address */ @NotBlank(groups = {AddGroup.class}) @URL(message = "logo Must be a legal url address",groups={AddGroup.class,UpdateGroup.class}) private String logo; /** * introduce */ private String descript; /** * Display status [0-not displayed; 1-displayed] */ // @Pattern() @NotNull(groups = {AddGroup.class, UpdateStatusGroup.class}) @ListValue(vals={0,1},groups = {AddGroup.class, UpdateStatusGroup.class}) private Integer showStatus; /** * Retrieve initials */ @NotEmpty(groups={AddGroup.class}) @Pattern(regexp="^[a-zA-Z]$",message = "The search initial must be a letter",groups={AddGroup.class,UpdateGroup.class}) private String firstLetter; /** * sort */ @NotNull(groups={AddGroup.class}) @Min(value = 0,message = "Sort must be greater than or equal to 0",groups={AddGroup.class,UpdateGroup.class}) private Integer sort; }
6. Alibaba cloud storage (oss)
Show an example of cloud storage (this is divided into version 1 and version 2. Problems introduced in version 1 can be solved with version 2)
Version one
pom.xml
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alicloud-oss</artifactId> </dependency>
application.yml
spring: cloud: nacos: discovery: server-addr: 127.0.0.1:8848 alicloud: access-key: [Fill in your own] secret-key: [Fill in your own] oss: endpoint: [Fill in your own] bucket: [Fill in your own]
Specific display methods
@RestController public class OssController { @Autowired OSS ossClient; @Value("${spring.cloud.alicloud.oss.endpoint}") private String endpoint; @Value("${spring.cloud.alicloud.oss.bucket}") private String bucket; @Value("${spring.cloud.alicloud.access-key}") private String accessId; @RequestMapping("/oss/policy") public R policy() { String host = "https://" + bucket + "." + endpoint; // The format of host is bucketname endpoint // callbackUrl is the URL of the upload callback server. Please configure the following IP and Port as your own real information. // String callbackUrl = "http://88.88.88.88:8888"; String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); String dir = format + "/"; // Prefix specified when the user uploads the file. Map<String, String> respMap = null; try { long expireTime = 30; long expireEndTime = System.currentTimeMillis() + expireTime * 1000; Date expiration = new Date(expireEndTime); PolicyConditions policyConds = new PolicyConditions(); policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000); policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir); String postPolicy = ossClient.generatePostPolicy(expiration, policyConds); byte[] binaryData = postPolicy.getBytes("utf-8"); String encodedPolicy = BinaryUtil.toBase64String(binaryData); String postSignature = ossClient.calculatePostSignature(postPolicy); respMap = new LinkedHashMap<String, String>(); respMap.put("accessid", accessId); respMap.put("policy", encodedPolicy); respMap.put("signature", postSignature); respMap.put("dir", dir); respMap.put("host", host); respMap.put("expire", String.valueOf(expireEndTime / 1000)); // respMap.put("expire", formatISO8601Date(expiration)); } catch (Exception e) { // Assert.fail(e.getMessage()); System.out.println(e.getMessage()); } return R.ok().put("data",respMap); } }
Version 2
pom.xml
<!-- introduce oss Related dependencies of--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>aliyun-oss-spring-boot-starter</artifactId> <version>1.0.0</version> <exclusions> <!-- exclude aliyun-java-sdk-oss Version too low --> <exclusion> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-oss</artifactId> </exclusion> <!-- exclude aliyun-sdk-oss,The version is too low. It's 3.1 Version--> <exclusion> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> </exclusion> </exclusions> </dependency> <!-- Import new dependencies--> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.7</version> </dependency> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.10.2</version> </dependency> <!-- introduce Oss End of dependency--> <dependencyManagement> <dependencies> <!-- Resolve import aliyun-oss-spring-boot-starter Import dependency error unknown --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>aliyun-spring-boot-dependencies</artifactId> <version>1.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
application.properties
management.endpoints.jmx.exposure.include=* management.endpoints.web.exposure.include=* management.endpoint.health.show-details=always # spring cloud access&secret config # You can visit the following address to view: https://usercenter.console.aliyun.com/#/manage/ak # Alibaba oss object storage alibaba.cloud.access-key=[Fill in your own] alibaba.cloud.secret-key=[Fill in your own] alibaba.cloud.oss.endpoint=[Fill in your own] alibaba.cloud.oss.bucket=[Fill in your own]
The specific calling methods are consistent, and you can also refer to the official technical documents
7. Data verification (JSR303 and user defined)
The verification is divided into JSR303 and user-defined verification
pom.xml (parent touch fast)
<!-- java Annotation verification start--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.17.Final</version> <scope>compile</scope> </dependency> <!-- java Annotation verification end-->
Refer to the first small point and the fifth small point for specific use
8. Use enumeration to control magic value
Simple example (parent module)
public class WareConstant { public enum PurchaseStatusEnum{ CREATED(0,"newly build"),ASSIGNED(1,"Assigned"), RECEIVE(2,"Received"),FINISH(3,"Completed"), HASERROR(4,"Abnormal"); private int code; private String msg; PurchaseStatusEnum(int code,String msg){ this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } } public enum PurchaseDetailStatusEnum{ CREATED(0,"newly build"),ASSIGNED(1,"Assigned"), BUYING(2,"Purchasing"),FINISH(3,"Completed"), HASERROR(4,"Purchase failure"); private int code; private String msg; PurchaseDetailStatusEnum(int code,String msg){ this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } } }
9. Centralized processing of global exceptions and slf4j log management
/** * Centralized processing of all exceptions */ @Slf4j @RestControllerAdvice(basePackages = "com.walid.product.controller") public class WalidExceptionControllerAdvice { @ExceptionHandler(value= MethodArgumentNotValidException.class) public R handleVaildException(MethodArgumentNotValidException e){ log.error("There is a problem with data verification{},Exception type:{}",e.getMessage(),e.getClass()); BindingResult bindingResult = e.getBindingResult(); Map<String,String> errorMap = new HashMap<>(); bindingResult.getFieldErrors().forEach((fieldError)->{ errorMap.put(fieldError.getField(),fieldError.getDefaultMessage()); }); return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap); } @ExceptionHandler(value = Throwable.class) public R handleException(Throwable throwable){ log.error("Error:{}",throwable); return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg()); } }