Category management microservice development

Starting from this chapter, we will develop specific micro-services according to each example project of e-commerce platform, mainly including category management, inventory management, order management, etc. In these sample projects, we will use different databases according to the characteristics of the project itself. For category management, we will use a secondary classification design, where there is some correlation between Data entities, so the best choice is to use Spring Data JPA for development. Spring Data JPA is a database development method recommended by default in the Spring Boot development framework, and it is also a specific application of domain-driven design.

Projects in this chapter can be checked out using Git in IDEA using the source code in this article. The project consists of three modules:

  • Catalog-object: Public object design for the class.
  • Catalog – RestAPI: Category interface development.
  • Catalog – Web: Web application for category management.

Understand domain driven design

Domain-driven Design (DDD) is a software development method based on business model and object-oriented modeling. Compared with process-oriented and data-structure-oriented design methods, object-oriented modeling decoupled the isolation between system analysis and system design fundamentally, thus improving the work efficiency of software development.

We will use JPA to implement a development approach to domain-driven design. JPA builds a data model of domain business objects through entity definitions, and then rapidly develops domain business functions by using repositories to give entities operational behaviors.

Hierarchical structure of DDD

DDD divides the system into user interface layer, application layer, domain layer, and infrastructure layer, as shown in Figure 6-1.

The application layer is a very thin layer, which is responsible for receiving the parameters from the user interface layer and routing to the corresponding domain layer. The business logic of the system is mainly concentrated in the domain layer, so the domain layer occupies a large area in the system architecture. Interfaces should be used to communicate between the upper and lower layers, so that the location of the interface definition determines the dependency between the upper and lower layers.

The basic elements of DDD

The basic elements of DDD include Entity, Value Object, Service, Aggregate, Repository, Factory, DomainEvent, and Moudle.

  • Entity: Indicates an Entity.
  • Value Object: indicates an Object with no status. Service: Can contain the behavior of an object.
  • Aggregate: A collection of related objects. Repository: a Repository.
  • Factory: A Factory that generates aggregate objects. Domain Event: indicates a Domain Event.
  • Moudle: indicates a module.

Spring Data JPA

Java Persistence API (JPA) is an interface specification for Java Persistence layer development. ORM frameworks such as Hibernate, TopLink and OpenJPA all provide implementations of JPA. The implementation of Spring Data JPA uses the Hibernate framework, so the design is not very different from using Hibernate directly. But JPA is not the same as Hibernate, it is a general specification on top of Hibernate.

Next, we illustrate the development approach to Spring Data JPA through the module Catalog-rest API.

Druid Data source configuration

Druid is an open source data source service component of Alibaba. It not only has good performance, but also provides monitoring and security filtering functions.

You can create a configuration class called DruidConfiguration to enable monitoring and filtering for Druid.

@Configuration public class DruidConfiguration { @Bean public ServletRegistrationBean statviewServle({ ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet (), "/druid/*"); / / IP address whitelisting servletRegistrationBean. AddInitParameter (" allow ", "192.168.0.1, 127.0.0.1"); / / IP address list (common existence, deny prior to allow) servletRegistrationBean. AddInitParameter (" deny ", "192.168.110.100"); / / management console user servletRegistrationBean addInitParameter (" loginUsername ", "druid"); servletRegistrationBean.addInitParameter ("loginPassword","12345678"); / / whether to reset the data servletRegistrationBean addInitParameter (" resetEnable ", "false"); return servletRegistrationBean; } @Bean public FilterRegistrationBean statFilter(){ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean (new webStatFilter()); / / add filter rules filterRegistrationBean. AddUrlPatterns (" / * "); The format of the / / ignore filter filterRegistrationBean. AddInitParameter (" exclusions ", "*.js,*.gif,* .jpg,* .png,*.Css,* .ico,/druid/* ")F return filterRegistrationBean; }}Copy the code

After using this monitoring configuration, when the application is running, for example, we start the catalog-Rest API module to open the monitoring console page with the following link:

http://localhost:9095/druid
Copy the code

In login authentication, enter druid/12345678, the user name and password configured in the preceding code. The login page shown in Figure 6-2 is displayed. Note that the local P address is not in the blacklist set up in the previous code.

After using the monitor console, you can view the results of “SQL Monitor” to provide a valuable reference for the SQL design and optimization of your application.

We can use the application. Yml configuration file in our project to set up Druid to connect to the data source as follows:

spring: datasource: driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/catalogdb? CharacterEncoding =utf8&useSSL=false username: root password:12345678 # InitialSize: 5 5 maxActive: 20 # configuration for connecting waiting timeout time maxwait: 60000 # configuration between how long a detection, testing needs to be closed free connection, unit is mstimeBetweenEvictionRunsMillis: 60000 # configure a connection in the pool minimum survival time, unit is msminEvictableIdleTimeMillis: 300000 validationquery: SELECT 1 FROM DUALtestWhileIdle: TestOnBorrow: falsetestOnReturn: false # Enable PSCache and specify the PSCache size for each connection poolPreparedStatements: True maxPoolPreparedStatementPerConnectionSize: # 20 configuration monitoring statistics of intercepting filters, if removed, the monitoring interface SQL will be unable to statistics, "wall" used in a firewall filters: Stat, Wall, log4j # Enable mergeSql via connectProperties; ConnectionProperties: druid.stat. MergeSql =true; druid.stat.slowSqlMillis=5000Copy the code

This section describes how to set the connected database, the user name and password of the database, and ensure that the database user configuration information is correct and has read and write permissions. Other configurations can be set by Druid’s general parameters.

The data source configuration also applies to the development of MyBatis.

JPA initialization and basic configuration

First, we create a configuration class JpaConfiguration that initializes some JPA parameters as follows:

econfiguration @EnableTransactionManagement (proxyTargetClass = true) @EnableJpaRepositories (basePackages = "com.** .repository")CEntityScan(basePackages = "com.* *.entity") public class JpaConfiguration{ @Bean PersistenceExceptionTranslationPostProcessorpersistenceExceptionTranslationPostProcessor(){ return new PersistenceExceptionTranslationPostProcessor(); }}Copy the code

In this case, we set the repository location to “com.**. Repository” and the entity location to “com.**. Entity” so that JPA can find the repository and entity objects we defined.

Then, in the application configuration file, add the following configuration:

spring:
jpa:
database: MYSQLshow-sql: false
## Hibernate ddl auto (validate lcreate l create-drop l update)hibernate:
ddl-auto: update
#naming-strategy:org.hibernate.cfg. ImprovedNamingStrategynaming.physical-strategy:
org.hibernate.boot.model.naming. PhysicalNamingStrategystandardImpl
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL5Dialectenable_lazy_load_no_trans: true
Copy the code

Ddl-auto is set to Update, indicating that the table structure will be updated when the entity attributes are changed. If the table structure does not exist, it is created. Be careful not to set “Dcl-auto” to “create”, otherwise the program will recreate the table structure every time it starts and the previous data will be lost. If automatic is not used, it can be set to “None”. The last line of code in the above configuration turns on Hibernate’s lazy loading capability, which improves access performance when querying relational relationships.

Entity modeling

When Spring Data JPA is used for entity modeling, Hibernate’s object relational mapping (ORM) is mainly used. In the category management project we need to create two entities, a primary class and a secondary class.

The main class consists of attributes such as name, operator, and creation date, and is implemented as follows:

@Entity @Table(name ="tsorts") public class Sorts implements java.io.Serializable { CId @Generatedvalue(strategy = GenerationType. IDENTITY)private Long id; private string name; private string operator; @DateTimeFormat (pattern = "Yyyy-MM-dd HH:mm:ss") eColumn (name = "created",columnDefinition = "timestamp defaultcurrent  timestamp") @Temporal (TemporalType.TIMESTAMP)private Date created; coneToMany(cascade = CascadeType.REMOVE)@OrderBy("created asc") CJoincolumn (name= "sorts id") private Set<Subsorts> subsortses = new HashSet<>();Copy the code

As you can see from the code above, we use the table “t_sorts” to store the data and it is associated with the secondary classification in a one-to-many fashion. The association is “sorts_id”, which will be stored in a table of secondary classifications. Additionally, when querying this relationship, we specify a sort by creation time “created”.

A secondary classification entity consists of attributes such as name, operator, and creation date, with codes as follows:

@Entity @Table(name ="tsubsorts") public class Subsorts implements java.io.Serializable t @Id @Generatedvalue(strategy =  GenerationType. IDENTITY)private Long id; private string name; private String operator; @DateTimeFormat (pattern = "Yyyy-MM-dd HH:mm:ss") @Column (name = "created",columnDefinition = "timestamp defaultcurrent_timestamp") @Temporal (TemporalType.TIMESTAMP)private Date created; . }Copy the code

Secondary classifications use a table structure called T_subsorts to store the data, and the field definitions are almost identical to those of the main class.

In the design of the above two entity objects, we realize the association design with the secondary classification through the main class in a one-to-many way, so that when the query in the main class, the data of the secondary classification can be obtained at the same time; The storage and update of the main class will also automatically involve categorization operations.

Regarding the design of entity modeling, especially the design of associative relationships, we will focus on the following important functions.

(1) The entity object must have a unique identity.

The Long type is used here to define the object’s identity “ID,” and this “ID” will be automatically generated by the database. In practical applications, it is recommended to use UUID as the unique identifier of an object, which can not only keep the consistency of the length of the field, but also ensure the uniqueness of the identifier in the whole database, and is very beneficial to the cluster design of the database.

(2) The date attribute should use the correct format.

Using the annotation “@datetimeFormat” to format the date ensures not only that the date is displayed correctly, but also that the date is correct in parameter passing. Note that the creation date “created” above uses the default setting.

(3) Use reasonable association Settings.

Association Settings are key to entity design. In order to avoid recursive calls, it is best to use one-way association Settings, that is, only one of the two objects associated with each other.

In general, a many-to-many association can use an intermediate table to store the association, while a one-to-many or many-to-one association can use a field to store the foreign key of the associated object. For example, in the entity design above, we use “sorts_id” as the foreign key associated with the primary class for the secondary classification.

In the association setting of the main class entity, we also use the cascading action setting: “cascadetype.remove”. This way, when a category in the main class is deleted, all categories associated with it are automatically deleted.

The options available for setting up cascades are as follows:

  • Cascadetype. PERSIST: cascading save.
  • Cascadetype. REMOVE: cascading deletion.
  • Cascadetype. MERGE: level MERGE and (update).
  • CascadeType.DETACH: cascading DETACH/dissociation.
  • Cascadetype. ALL: indicates ALL the previous cascading operations.

Query object design

We put the query object design in a common module, the catalog-Object, so that the other two modules can be called. Query Objects (QO) are used to distinguish them from VO. Some people think of VO as a ValueObject, and some people think of VO as a View Object, so it is easy to misunderstand. The meaning and purpose of these two objects are different. Value objects represent some data different from entities and can be displayed as views. A view object is a type of data that can only be displayed as a view.

Because an entity has a life cycle and state, and its state directly affects the data stored, we use a stateless data object to store the entity’s data. The use and change of this data does not directly affect the data store, so it is either safe to use or disposable.

We can use a query Object as a value Object, a query Object as a view Object, or as a collection of query parameters, which is equivalent to a Data Transfer Object (DTO).

We can include vo, DTO, and so on with a single query object qO, which is a simplified design. Qos sometimes contain redundant data, but this is of little consequence to users. For example, our query object will contain paging properties such as page numbers and page sizes that are not needed in the view display, so it can ignore them.

With respect to the main class entity, its query object is designed as follows:

public class SortsQ0 extends PageQ0 { private Long id; private String name; private String operator; @DateTimeFormat (pattern = "yyyY-MM-dd HH:mm :ss")private Date created; private List<SubsortsQ0> subsortses = new ArrayList<>(); . }Copy the code

Where, it inherits the PageQo query object will provide two paging query parameters, the implementation code is as follows:

public class PageQ0 [
private Integer page = 0;private Integer size = 10;
...
}
Copy the code

In the paging parameter, there is only a page number and a page size setting for two fields.

Data persistence design

Using JPA entity data persistence design is relatively easy, as long as as entities create a repository interface, JPA repository interfaces with the entity object binding, can realize the design of data persistence entity, equivalent to the entity gives some actions to access the database, including basic operations such as add and delete.

In addition to the basic operation of the data store, we can also declare the query interface according to the field name of the entity, and for some complex queries, we can also use THE SQL query language design. The storage interface design of the entity main class is as follows:

@Repository
public interface SortsRepository extends JpaRepository<Sorts,Long>,JpaSpecificationExecutor<Sorts> {
Page<Sorts> findByNameLike (@Param ( "name ") string name,PageablepageRequest);
@Query("select t from Sorts t where t.name like :name and t.created=:created")
Page<Sorts> findByNameAndCreated(@Param ("name") String name,@Param ("created") Date created, Pageable pageRequest);
Sorts findByName (@Param("name") String name);
@Query ( "select s from Sorts s"+
"left join s.subsortses b"+"where b.id= :id")
Sorts findBySubsortsId(@Param( "id") Long id);
}
Copy the code

This interface definition is not for us to implement, as long as the method definition conforms to JPA’s rules, JPA can do the rest of the work.

In JPA, you can customize the method declaration rules by using the keywords findBy.readBy, getBy, etc. as the prefix of the method name in the interface, concatenating the attribute fields in the entity class (the first letter is capitalized), and finally concatenating some SQL query keywords (or not) to form a query method. Here are some examples of query keywords:

  • And, for example findByIdAndName(Long ID, String name);
  • Or, for example, findByldOrName (Long ID, String name);
  • Between, for example, findByCreatedBetween(Date start,Date end); LessThan, for example findByCreatedLessThan(Date start);
  • GreaterThan, for example findByCreatedGreaterThan(Date start); IsNull, for example findByNameIsNull();
  • IsNotNull, for example findByNamelsNotNull();
  • NotNull, equivalent to IsNotNull;
  • Like, for example findByNameLike(String name);
  • NotLike, for example findByNameNotLike(String name);
  • OrderBy, for example findByNameOrderByIdAsc(String name); Not, for example findByNameNot(String name);
  • In, for example, findByNameIn(Collection nameList);
  • NotIn, for example, findByNameNotIn(Collection nameList).

A Query designed using the SQL Query language through the @query annotation is basically the same as a database Query, except that the name of the entity object is used instead of the name of the database table.

In the repository interface definition above, we inherit not only from JPA’s base repository, JpaRepository, but also from a more specialized repository, JpaSpecificationExecutor, through which we can do some complex paging design.

Data management service design

The previous persistence design has established an access relationship between the entity and the database. To better provide external data access services, we need to encapsulate the calls to the repository again. In this encapsulation, we can implement unified transaction management and its paging query design. The classified data management service design code is as follows:

@Service @Transactional public class SortsService { @Autowired private SortsRepository sortsRepository; public Sorts findOne (Long id){ Sorts sorts =sortsRepository.findById(id).get(); return sorts; public Sorts findByName (string name){ return sortsRepository.findByName (name) ; } public String save (Sorts sorts){ tryi sortsRepository.save(sorts); return sorts.getId() .toString(); }catch(Exception e){ e.printStackTrace(); return e.getMessage(); } public String delete (Long id){ try{ sortsRepository.deleteById(id); return id.toString(); Jcatch(Exception e){ e.printStackTrace(); return e.getMessage (); public Page<Sorts> findAll (SortsQo sortsQo){ Sort sort = new Sort (Sort.Direction. DESC, "created"); Pageable pageable = PageRequest.of (sortsQo.getPage (), sortsQo.getSize(), sort); return sortsRepository.findAll (new Specification<Sorts>()1 @override public Predicate toPredicate (Root<Sorts> root, CriteriaQuery<? >query, CriteriaBuilder criteriaBuilder) { List<Predicate> predicatesList =new ArrayList<Predicate>(); if(CommonUtils.isNotNull (sortsQo.getName()){ predicatesList.add (criteriaBuilder.like(root.get ("name"), "No." + sorts0o. GetName () + "%")); } if(CommonUtils.isNotNull (sortsQo.getCreated())){ predicatesList.add (criteriaBuilder.greaterThan (root.get ("created"),sortsQo.getCreated())); } query.where(predicatesList.toArray (new Predicate[predicatesList.size()])); return query.getRestriction(); }, pageable); }}Copy the code

In the above code, implicit transaction management is implemented using the @Transactional annotation, which calls the methods of the repository interface directly for some basic data operations.

In the code above, the design of paging queries is implemented using the findAll method. In this design, you can define sorting methods and fields, set page numbers and lines per page, and dynamically set query conditions based on query parameters. Here, we can either do a fuzzy query by the name of the category or a qualified query by the time the category was created.

Unit testing

After completing the design in the previous section, we can write a test case to validate the design of the domain service. It is important to note that because there is already a configuration to update the table structure in the previous JPA configuration, if the table structure does not exist, it will be generated automatically; If the table structure is updated, the launcher is updated automatically. The following test case demonstrates how to insert data for categories and main classes:

@RunWith(SpringJUnit4ClassRunner.class) eContextConfiguration (classes = {UpaConfiguration.class,SortsRestApiApplication.class}) @SpringBootTest public class SortsTest{ private static Logger logger = LoggerFactory.getLogger (SortsTest.class); CAutowired private SortsService sortsService; @Autowired private SubsortsService subsortsService; @Test public void insertData() { Sorts sorts =new Sorts(); Sorts. Elegantly-named setName (" books "); Sorts. SetOperator (" editor "); sorts.setCreated(new Date()); // Sorts = sortsService.findByName(" book "); Subsorts subsorts = new Subsorts(); Subsorts. SetName (" computer "); subsorts.setOperator("editor"); subsorts.setCreated(new Date()); subsortsService.save (subsorts); Assert.notNull(subsorts.getId(), "insert sub error"); sorts.addSubsorts(subsorts); sortsService.save(sorts); Assert.notNull (sorts.getId(), "not insert sorts"); }... }Copy the code

Test cases for other queries can be designed in this way, and if the assertion has no errors, the test is as expected, that is, no error messages are presented. In a debug environment, console information can also be used to analyze the process of testing.

Category interface microservice development

Category interface microservice is an independent microservice application, which provides some interface services related to category query and category data management by using the way of REST protocol. This interface service can not only be used in the design of category management in the business background, but also in the design of mobile terminal, App or other client programs.

When the above unit testing is complete, we can use the data services provided in the above design to develop the category interface microservices.

RESTful Interface Development

We will follow the REST protocol specification design based on RESTful interface development, for example, for classification, we can design the following request:

  • GET/sorts/{ID}: Gets the details of a category by ID; GET /sorts: Queries the paging list of categories;
  • POST/SORTS: Creates a new category; PUT /sorts: Updates a category;
  • DELETE /sorts/{ID}: Deletes a category by ID.

The following code shows a partial implementation of the classification interface design. The complete code can be viewed in the project source code:

@RestController @RequestMapping("/sorts") public class SortsController { private static Logger logger = LoggerFactory.getLogger(SortsController.class); @Autowired private SortsService sortsService; @GetMapping (value="/{id] ") public String fnidById(@PathVariable Long id){ return new Gson().toJson (sortsService.findOne (id)); ) @GetMapping () public String findAll(Integer index,Integer size, String name) try { SortsQo sortsQ0 = new SortsQ0(); if(CommonUtils.isNotNul1(index)){ sortsQo .setPage(index); } if(CommonUtils.isNotNull(size)){ sortsQ0.setsize(size); } if(CommonUtils.isNotNul1 (name)){ sortsQo. setName(name); } Page<Sorts> orderses = sortsService.findAll(sortsQo); Map<String, 0bject> page = new HashMap<>(); page.put( "content", orderses.getContent(); page.put ("totalPages", orderses.getTotalPages()); Page. The put (" totalelements ", orderses getTotalElements ()); return new Gson() .toJson (page); } Jcatch(Exception e){ e.printStackTrace(); } return null; ) @PostMapping() public String save (CRequestBody SortsQo sortsQo) throws Exception{t Sorts sorts =new sorts(); BeanUtils.copyProperties (sortsQ0,sorts); sorts.setCreated (new Date()); List<Subsorts> subsortsList = new ArrayList<>(); For (SubsortsQo subsortsQ0: sortsqo.getSubsortses ()){Subsorts Subsorts =new Subsorts(); BeanUtils.copyProperties(subsortsQ0,subsorts); subsortsList.add(subsorts); ) sorts. setSubsortses (subsortsList); String ret =sortsService.save(sorts); Logger. info(" add ="+ ret); return ret; }... }Copy the code

In the microservice interface design above, RestController is used to define the URL interface to provide services externally, and the data access in the interface is realized by calling various methods of SortsService. JSON data structures are used to transfer data in the interface calls, so JSON data structures are used explicitly or implicitly in the above code. For a data object, to ensure the integrity of its data, we usually use the GSON tool to perform explicit transformation of the data.

It is important to note that since query objects are used in data transfer, they need to be converted into entity objects when data is saved and updated.

Microservice interface debugging

Once the microservice interface is developed, you can launch the project’s application for simple debugging. For the class microservice interface, we can start the main program SortsRestApiApplication in the catalog-rest API module for debugging.

After successful startup, some GET requests can be debugged directly from the browser.

For example, you can view information about a category by category ID using the following link address:

http://localhost:9091/sorts/1
Copy the code

If the data exists, the JSON data shown in Figure 6-3 is returned.

To query data on the first page of a page, use the following link address:

http://localhost:9091/sorts
Copy the code

If the query succeeds, the information shown in Figure 6-4 is displayed.

Because requests such as POST and PUT require parameters to be transferred during debugging, they cannot be tested directly using a browser, but you can debug them using tools such as Postman.

RESTful microservice interface invocation

There are several ways to invoke RESTful interface-based services. For example, you can use HTTP access (such as HttpClient), or use RestTemplate as a call, and so on. However, in microservice applications, the best approach is to use a declarative FeignClient.

Because FeignClient is invoked for other microservices, these designs are developed here in the module catalog-Object.

Declarative FeignClient design

FeignClient is a declarative client. To use this tool component, we need to introduce FeignClient’s dependencies into the project object model, as shown below:

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId></dependency>
Copy the code

For the main class interface invocation, we can define an interface program SortsClient that declares some invocation methods according to the interface service provided by the catalogAPI using the following methods:

@feignClient ("catalogapi") public interface SortsClient {@requestMapping (method = requestmethod.get, Value = "/sorts/{id}")String findById(CRequestParam(" ID ") Long ID); @RequestMapping (method = RequestMethod.GET,value = "/sorts/findAll")String findList(); CRequestMapping (method = RequestMethod.GET, value = "/sorts", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces =MediaType.APPLICATION_JSON_UTF8_VALUE) String findPage (CRequestParam("index") Integer index, @requestParam ("size") Integer Size, @requestParam (" name") String name); @RequestMapping (method =RequestMethod.GET, value = "/sorts/findAll", consumes = MediaType.APPLICATION JSON UTF8_VALUE, produces = MediaType.APPLICATION_ JSON_UTF8_VALUE) String findAll(); @RequestMapping (method = RequestMethod. POST, value = "/sorts", consumes = MediaType.APPLICATION_JSON UTF8 VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) String create(@RequestBody SortsQ0 sortsQ0) ; @RequestMapping (method = RequestMethod.PUT,value = "/sorts", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_ UTF8_VALUE) String update(@RequestBody SortsQo sortsQo); @RequestMapping (method = RequestMethod. DELETE,value = "/sorts/{id}")String delete (@RequestParam("id") Long id); }Copy the code

In this implementation code, you first reference the microservice CatalogAPI with the @FeignClient annotation, and then declare the invocation method directly using its exposed URL. It should be noted that the data transmission, namely the production and consumption of data, is carried out in JSON format, so in order to ensure the correctness of Chinese characters, we use UTF8 encoding.

Use of circuit breakers

Based on the declaration method of SortsClient, we can create a service class SortsRestService to call. Then, using the functionality provided by SortsRestService, you can use the interface methods provided by the catalogAPI microservice as if you were using native methods. The implementation code of the service class SortsRestService is as follows:

@service public class SortsRestService { CAutowired private SortsClient sortsClient; @HystrixCommand (fallbackMethod = "findByIdFallback")public String findById(Long id){ return sortsClient.findById(id); private String findByIdFal1back (Long id){ SortsQo sortsQo = new SortsQ0(); return new Gson() .toJson (sortsQo); }... }Copy the code

In the code above, we implement a call to SortsClient and add an annotation @hystrixCommand. With this annotation, a fallback method is defined. The design of this step back method is the implementation method of circuit breaker function provided by SpringCloud component. The idea of a circuit breaker is to reduce the load on a service when it is overloaded or unavailable by downgrading the call or by failover. Here we use a fallback method design to quickly respond to the access from the client and to ensure that the client’s access to the microservice does not collapse due to a failure. The design of the circuit breaker is just like the protective switch of the circuit, which can protect the system service. Unlike the protection switch, the circuit breaker automatically fails when the system returns to normal without human intervention.

Category management Web application microservice development

Here category management is a PC-based Web application, which is also an independent microservice application. This application is implemented in the project project module, catalog-Web, which can be viewed as a separate project.

In this application, we will demonstrate how to use the services provided by the category management micro-service interface to develop related application functions, so as to achieve a friendly operation interface for category management on PC.

Configuration of interface invocation references

The above interface invocation services were developed in the module catalog-object. To use these services in the module “catalog-web”, you must first configure the reference in the project object model, as shown below:

<dependency>
<groupId>com.demo</groupId>
<artifactId>catalog-object</artifactId><version>${project.version}</version></dependency>
Copy the code

Because both modules are in the same project, the version referenced above uses the project version directly. This way, when the interface service is started, we can make related calls in subsequent Web applications.

It is important to note that if more than one FeignClient program calls the same microservice interface service, it must be set up in the project’s configuration file with the configuration shown below to support this invocation. Because the default configuration of this Spring Cloud release does not enable this invocation:

Allow multiple interfaces to use the same service

spring:
main:
allow-bean-definition-overriding: true
Copy the code

Spring MVC controller design

Spring MVC is a fundamental component of Web application development, and let’s use this group to design a controller. In the design of the main class controller for the Web application, we directly use the service class designed above :SortsRestService. We can use the SortsRestService class as a native method to directly invoke the interface service provided by the microservice, as shown below:

@GRestController @RequestMapping ( "/sorts") public class SortsController { private static Logger logger = LoggerFactory.getLogger(SortsController.class); @Autowired private SortsRestService sortsRestService; @GetMapping(value=" /index") public Mode1AndView index(){ return new ModelAndview( "sorts/index"); @GetMapping (value="/{id]") public ModelAndView findById(@PathVariable Long id){ return new ModelAndView("sorts/show", "sorts", new Gson() .fromJson (sortsRestService.findById(id), SortsQo.class)); }... }Copy the code

The findByld method in the code above is a design that uses a page to display categorization information. In this design, on the one hand, the service class SortsRestService designed above is referenced, and its findByld method is called to conduct data query; On the other hand, the query data is displayed via a show page. This design differs from a normal local call in that the value returned when the data is queried is an ISON structure, so it must be converted to a query object for easy use.

The following page design will use the functionality of Thymeleaf templates.

Use the Thymeleaf template

We will use the Thymeleaf template in our Web application page design, so we must introduce the Thymeleaf dependency in the catolog-Web module as follows:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId></dependency> <dependency> < the groupId > nz.net.ultraq.thymeleaf < / groupId > < artifactId > thymeleaf - layout - the dialect < / artifactId > < version > 2.3.0 < / version > </dependency>Copy the code

For Thymeleaf configuration, use its default configuration, as long as you have the static and templates directories in your application’s resources directory. These directories are used to store static files and template designs and their page design files, which are suffixed with HTML by default.

HTML page design

In the design of the controller in Section 6.10, the output of the category information is a show page, which is designed in the show.html file, and the code is as follows:

< HTML XMLNS :th="http://www.thymeleaf.org"><div class="addInfBtn"> <h3 class="itemTit"><span> Category information </span></h3><table Class ="addNewInfList"> <tr> <th> < TD width="240"><input class="inp-list w-200 clear-mr F-left "type="text" Th :value="${sorts. Namel "Readonly ="true"/></td> <th> operator </th> < TD ><input class="inp-list w-200 clear-mr F-left" Type ="text" th:value="${sorts. Operator}" readOnly ="true"/></td> </tr> <tr> <th> subclass </th>< TD >< select multiple= "multiple"  readonly="true"> <option th:each="subsorts:${sorts.subsortses] " th:text="${#strings. length(subsorts.name) > 20? # strings. The substring (0, 20 subsorts. The name) + '... Th :selected="true" ></option> </select> </ TD >< th> date </th>< TD >< input onfocus="WdatePicker ({dateFmt:'yyyy-MiM-dd HH :mm:ss'))" type="text" class="inp-list w-200 clear-mr f-left" th:value="${sorts.created)?$ {#dates.format(sorts.created, 'vyvy-MM-dd HlH:mm:ss')}:''" readonly="true"/> </td> </tr></table> <div class="bottomBtnBox"> <a class="btn-93x38 BackBtn "href="javascript:closeDialog (0)"> Returns </a></div>Copy the code

As you can see from the code above, the design is the same as the normal HTML tag language, except for the specific use of Thymeleaf. After the design, the final effect of the page is shown in Figure 6-5.

Unified style template design

A more powerful feature of Thymeleaf is to provide a uniform style of template design, that is, the entire site can use a uniform style of framework structure. In the project of category management, the general page framework design layout.html is used, and the code is as follows:

<! DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"> <body> <div class="headerBox"> <div class="topBox"> <div class="topLogo f-left"> <a href="#"><img Th: SRC ="@{/images/logo.pngl "/></a></div> </div></div> <div class="locationLine" layout:fragment="prompt"> <table class="globalMainBox" style="position:relative; z-index:1"> <tr> <td class="columnLeftBoX" valign="top"> <div th:replace="fragments/nav ::nav"></div></td> <td class="whiteSpace"></td> <td class="rightColumnBox" valign="top"><div layout: fragment="content"></div></td> </tr></table> <form th:action="@{/logout}" method="post" id="logoutform"></form> <div class="footBox" th:replace="fragments/footer :: footer"></div></body> </html>Copy the code

There is a status bar at the top of the page, a navigation bar on the left, a content display area in the middle, and a footer design at the bottom. After referencing the template, you simply overwrite the areas that need to be changed, and use the template’s default design for those that don’t. In general, when using this template, you can simply change the status bar and content display area, while the navigation bar and footer can use a common page design.

In this example, the category’s home page is designed to reference the template via the index.html page, as follows:

<! DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout" layout:decorator="fragments/layout"> <body> <! > > <div class="locationLine" layout: fragment="prompt"> > <div class="statisticBoX W-782 "layout:fragment="content"> </div></body></html>Copy the code

As you can see, in the above code, we only updated the design of the status bar and the main content display area, and kept the template design for the rest of the code.

In the above design explanation and demonstration, we only illustrate the design of the main class, the design of the secondary classification and the design of the main class are almost the same, no further details.

At this point, the development work of category management microservice application is basically completed.

Now we can experience the invocation between microservices, because it is developed using the Spring Cloud tool component, so the implementation in all aspects is very convenient. Of course, for the invocation of micro services, not only the call of Web applications, but also other applications such as App applications, wechat public accounts or small program clients, or the design of other languages, the call of heterogeneous environment, etc. No matter which tool is used for design, it is easy to invoke microservices using HTTP.

The overall test

With the category management microservice interface and its Web microservice application developed, we were ready for an overall test. Verify that Consul is running, and then start the catalog-Rest API and catalog-Web modules. After successful startup, use your browser to access the following url:

http://localhost:8091
Copy the code

If all is well, you can go to the main page for category management as shown in Figure 6-6. Here, we can add, delete, change and check all the categories in the main category and the secondary classification respectively.

Package and deploy projects

When you use the IDEA development tool for packaging, you can use Maven Project manager for packaging, as shown in Figure 6-7.

If the project is modular, be sure to package it in the root directory of the project so that the modules it depends on are packaged together.

When the packaging is complete, you can use the command terminal to switch to the target directory of the catalog-restAPI and catalog-Web modules respectively and run the following commands to start the application for debugging:

java -jar catalog*.jar
Copy the code

Starting the application in this way has the same effect as debugging the IDEA tool above. If it starts properly, you can perform the same tests as above.

This startup can also be used as a general way to publish microservices, and in a production environment, you can add some parameters for memory and log storage to the instructions above.

The deployment of microservice applications is described in detail in the o&M deployment section.

summary

This chapter introduces the development examples of two micro-services, the category management interface of e-commerce platform and the Web category management background. Through the development and demonstration of this project, we have made clear the method of fast communication and mutual call between micro-services. In the development of class management interface, we understand the working principle and implementation method of DDD development method in Spring development framework through Spring Data JPA development tool. Through the implementation of category management interface, we transform stateful data access behavior into stateless interface service.

In the next chapter, we will introduce another database development tool, MyBatis, and experience the application methods of different database development tools in Spring project engineering.

Three things to watch ❤️

If you find this article helpful, I’d like to invite you to do three small favors for me:

  1. Like, forward, have your “like and comment”, is the motivation of my creation.

  2. Follow the public account “Java rotten pigskin” and share original knowledge from time to time.

  3. Also look forward to the follow-up article ing🚀

  4. [666] Scan the code to obtain the learning materials package

Article is not original, and all of us feel while reading the article good remember thumb up forward + attention oh ~ this article source: www.toutiao.com/i6900833940…