Article directory
- 1. Automatically generate code
-
- 1.1 Install plug-in
- 1.2 Generate code
- 2. Db static tool class
-
- 2.1 Understanding of Db static tool class
- 2.2 Use cases of Db static tool class
- 3. Logical deletion
- 4. Enumeration processor
-
- 4.1 Define enumeration constants
- 4.2 Configure enumeration processor
- 4.3 Test field conversion of enumeration processor
- 5. JSON Processor
-
- 5.1 Define entities
- 5.2 Using type handlers
1. Automatically generate code
After learning the use of MyBatis Plus, we found that the basic Mapper
, Service
, PO
and other codes are basically fixed. If this is the case, it will be very troublesome to write code repeatedly. Coincidentally, MyBatis Plus officially provides a code generator to automatically generate Mapper
, Service
, and PO
for us based on the table structure of the database. code. However, the code generator also requires coding, which is also very troublesome. It is recommended that you use a Mybatis Plus plug-in, which can complete Mybatis Plus code generation based on the graphical interface, which is very simple.
1.1 Install plug-in
Search for “Mybatis Plus” in IDEA’s plugins and select which icon is particularly cute:
After successful installation, you can see an Orther
option in the navigation bar of IDEA:
This includes database configuration and code generation options.
1.2 Generate code
At this time, we happen to have a address
table that has not yet written the corresponding code. At this time, we can use this plug-in to automatically generate the code related to the address
table.
- First configure the database and fill in the basic information of the database connection in the pop-up window:
- Then click
other
in the IDEA navigation bar again and select Generate Code:
Click “code generatro” and the code will be automatically generated to the specified location.
2. Db static tool class
2.1 Understanding of Db static tool classes
Sometimes different Service classes call each other. In order to avoid circular dependency problems, Mybatis Plus provides a static tool class: Db
, some of which static methods are similar to IService
The method signatures are basically the same and can also help us implement CRUD functions:
For example, the following use case:
/** * Get user information with id 1 */ @Test void testDbGet() {<!-- --> User user = Db.getById(1L, User.class); System.out.println(user); } /** * Query user information with "o" in the user name and balance >= 1000 */ @Test void testDbList() {<!-- --> List<User> list = Db.lambdaQuery(User.class) .like(User::getUsername, "o") .ge(User::getBalance, 1000).list(); System.out.println(list); } /** * Set the balance of the user named Rose to 2500 */ @Test void testDbUpdate() {<!-- --> Db.lambdaUpdate(User.class) .set(User::getBalance, 2500) .eq(User::getUsername, "Rose").update(); }
It can be found that the use of the static class corresponding to Db
is similar to the previous use method.
2.2 Use cases of Db static tool class
Example 1: Modify the interface for user query based on id, and return the user’s delivery address list while querying the user.
- First, we need to add a VO object of the shipping address:
@Data @ApiModel(description = "Shipping address VO") public class AddressVO{<!-- --> @ApiModelProperty("id") private Long id; @ApiModelProperty("User ID") private Long userId; @ApiModelProperty("province") private String province; @ApiModelProperty("city") private String city; @ApiModelProperty("County/District") private String town; @ApiModelProperty("mobile phone") private String mobile; @ApiModelProperty("Detailed address") private String street; @ApiModelProperty("Contact") private String contact; @ApiModelProperty("Is it the default 1 default 0 no") private Boolean isDefault; @ApiModelProperty("Remarks") private String notes; }
- Then, transform the original
UserVO
class and add an address attribute at the end:
- Next, modify the business interface for querying users based on
id
inUserController
:
@GetMapping("/{id}") @ApiOperation("Query user interface based on id") public UserVO queryUserById(@PathVariable("id") Long id) {<!-- --> return userService.queryUserAndAddressById(id); }
At this time, a new queryUserAndAddressById
method has been added.
-
Implement the
queryUserAndAddressById
method in theservice
layer- First define the method in
IUserService
:
public interface IUserService extends IService<User> {<!-- --> UserVO queryUserAndAddressById(Long id); }
- Then, implement this method in
UserServiceImpl
:
@Override public UserVO queryUserAndAddressById(Long id) {<!-- --> // 1. Query user User user = getById(id); // 2. Use Db to query address categories based on users List<Address> addresses = Db.lambdaQuery(Address.class) .eq(Address::getUserId, user.getId()) .list(); // 3. Process VO UserVO userVO = BeanUtil.copyProperties(user, UserVO.class); userVO.setAddresses(BeanUtil.copyToList(addresses, AddressVO.class)); return userVO; }
- First define the method in
When querying the address, the static method in Db
is used, thus avoiding the injection of AddressService
and reducing the risk of circular dependencies.
After completing the above code, the user information queried through id
will have address information:
Example 2: Modify the interface for querying users in batches based on ID, requiring all addresses corresponding to the user to be queried
- Modify the
controller
interface:
@GetMapping @ApiOperation("Batch query user interface based on id") public List<UserVO> queryUserByIds(@ApiParam("User ID Collection") @RequestParam("ids") List<Long> ids) {<!-- --> return userService.queryUserAndAddressByIds(ids); }
-
Implement the
queryUserAndAddressByIds
method in theservice
layer- First define the method in
IUserService
:
public interface IUserService extends IService<User> {<!-- --> List<UserVO> queryUserAndAddressByIds(Long id); }
- Then, implement this method in
UserServiceImpl
:
@Override public List<UserVO> queryUserAndAddressByIds(List<Long> ids) {<!-- --> // 1. Query user collection List<User> users = this.listByIds(ids); if (users.isEmpty()) {<!-- --> return Collections.emptyList(); } // 2. Query address // 2.1 Get user id List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList()); // 2.2 Query address List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list(); // 2.3 Address converted to VO List<AddressVO> addressVOS = BeanUtil.copyToList(addresses, AddressVO.class); // 2.4 Group addresses VO according to userId Map<Long, List<AddressVO>> addressesMap = new HashMap<>(); if (CollUtil.isNotEmpty(addresses)) {<!-- --> addressesMap = addressVOS.stream().collect(Collectors.groupingBy(AddressVO::getUserId)); } // 3. Convert VO and return List<UserVO> list = new ArrayList<>(users.size()); for (User user : users) {<!-- --> UserVO userVO = BeanUtil.copyProperties(user, UserVO.class); // Fill in the address userVO.setAddresses(addressesMap.get(user.getId())); list.add(userVO); } return list; }
- First define the method in
Note:
-
When using the queried user ID to query address information, avoid querying the database in a loop. Therefore, the user ID collection is first obtained, and then the address information is queried in batches based on these ID collections.
-
Classify the queried address information according to user ID, and then set it into the corresponding
UserVO
object.
3. Logical deletion
For some more important data, we often use logical deletion solutions, such as:
-
Add a field to the table to mark whether data has been deleted
-
Set flag to true when deleting data
-
Filter out data marked true when querying
Once logical deletion is adopted, all query and deletion logic will change accordingly, and the corresponding database operations will become very troublesome. Fortunately, to solve this trouble, MyBatis Plus provides support for logical deletion.
Note that only the SQL statements generated by Mybatis Plus support automatic logical deletion. Custom SQL still requires manual processing of logical deletion.
The following demonstrates using the logical deletion function of MyBatis Plus:
- Add a tombstone field to the
address
table:
alter table address add deleted bit default b'0' null comment 'logical delete';
- Then add the
deleted
field to theAddress
entity:
- Next, configure the tombstone field in
application.yml
mybatis-plus: global-config: db-config: logic-delete-field: deleted # Logical delete field logic-delete-value: 1 # When the value of deleted is 1, it is logically deleted. logic-not-delete-value: 0 # When the value of deleted is 0, there is no logical deletion
After completing all the above preparations, we can execute a deleted test method:
@Test void testLogicDelete() {<!-- --> addressService.removeById(59L); }
Run this code:
It was found that the deleted
field of the address information with ID 59 was set to 1. If you query this data again at this time:
It is found that this data cannot be queried at this time, but it still exists in the database.
Therefore, after turning on the logical deletion function, we can do CRUD like normal deletion, basically without having to consider code logic issues. Still very convenient. However, there are certain problems with using logical deletion, such as:
- This will lead to more and more junk data in the database table, thus affecting query efficiency;
- All SQL requires judgment on tombstone fields, which affects query efficiency.
Therefore, it is not recommended to use the logical deletion function. If the data cannot be deleted, you can migrate the data to other tables.
4. Enumeration processor
There is a user status field in the User
entity class:
We usually define an enumeration for fields like this, and when making business judgments, we can directly make comparisons based on the enumeration. However, our database uses the int
type, and the corresponding PO is also Integer
. Therefore, you must manually convert enumerations and Integer
during business operations, which is very troublesome. Therefore, Mybatis Plus provides a type converter for processing enumerations, which can help us automatically convert enumeration types and database types.
4.1 Define enumeration constants
First, we define an enumeration constant for this status field in the user table:
@Getter public enum UserStatus {<!-- --> NORMAL(1, "normal"), FROZE(2, "Freeze"), ; private final int value; private final String desc; UserStatus(int value, String desc) {<!-- --> this.value = value; this.desc = desc; } }
Then change the status
field in the User
class to the UserStatus
type:
To let Mybatis Plus handle automatic conversion between enumeration and database types, we must tell Mybatis Plus which field value in the enumeration is used as the database value. Mybatis Plus provides the @EnumValue
annotation to mark enumeration properties:
4.2 Configuring the enumeration processor
Add the following configuration in the application.yml
file to enable the function of enumerating processors:
mybatis-plus: configuration: default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler # Enumeration processor
4.3 Test field conversion of enumeration processor
For example, query a user based on id:
At this time, the status of the
The fields will be of enumeration type.User
class is queried
At the same time, in order to make the page query results also in enumeration format, we need to modify the status
attribute in UserVO
:
And, pass @JsonValue in the
annotation tag JSON is serialized is UserStatus
enumeration The field displayed when the desc
:
Finally, query on the page and the results are as follows:
5. JSON Processor
There is a info
field in the user
table of the database, which is of JSON type:
The format is like this:
{<!-- -->"age": 20, "intro": "Buddhist youth", "gender": "male"}
But currently the User
entity class is of String
type, because there is no such type as JSON in Java:
As a result, it is very inconvenient for us to read the attributes in info
. If you want to easily obtain it, the type of info
is best to be a Map or entity class.
Once we change info
to an object type, we need to manually convert it to String when writing to the database, and then manually convert it to an object when reading the database, which will be very troublesome.
Therefore, Mybatis Plus provides many type processors for special types of fields to solve the problem of conversion between special field types and database types. For example, when processing JSON, you can use the JacksonTypeHandler
processor.
Next, let’s take a look at how to use this processor.
5.1 Define entities
First, we define a separate entity class to match the attributes of the info
field:
@Data @NoArgsConstructor @AllArgsConstructor public class UserInfo {<!-- --> private Integer age; private String intro; private String gender; }
5.2 Using type processors
Next, modify the info
field of the User
class to the UserInfo
type and declare the type processor:
Note that autoResultMap
needs to be set to true
for it to take effect.
The test can find that all data is correctly encapsulated into UserInfo
:
At the same time, in order to return the results returned by the page in object format, we need to modify the type of the info
field in UserVO
:
At this time, the query results on the page are as follows:
It is found that the info
displayed at this time is in JSON format.