Summary of basic knowledge of microservice

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());
    }


}

Keywords: Java Microservices

Added by Nexus10 on Fri, 18 Feb 2022 13:00:40 +0200