Preface
In Java Web development, paging and parameter verification are two very important functions. This article will focus onPagination designandParameter verificationConduct discussion, including how to design reasonable paging query parameters and how to use themJava AnnotationsImplement parameter verification.
Pagination design
Why do you need pagination?
When the data volume of database table is large, if you directly query all data, it may causeSlow query, and even causedMemory overflow (OOM). Pagination is a common optimization method that canReduce database loadandImprove front-end rendering speed。
How to design paging query parameters?
Pagination usually contains the following core parameters:
-
pageNo
: The current page number, default is1
。 -
pageSize
: The number of records returned per page, default is20
。 -
sortBy
: Sort fields, such asid
、create_time
。 -
isAsc
: Whether to ascending order, the default istrue
。
We can design a public parent classPageQuery
To help provide default parameters, we will also use mybatisplus in development to provide a method to convert it into a page object
@Data @ApiModel(description = "Pagination Request Parameters") @Accessors(chain = true) public class PageQuery { public static final Integer DEFAULT_PAGE_SIZE = 20; public static final Integer DEFAULT_PAGE_NUM = 1; @ApiModelProperty(value = "page number", example = "1") @Min(value = 1, message = "The page number cannot be less than 1") private Integer pageNo = DEFAULT_PAGE_NUM; @ApiModelProperty(value = "Page size per page", example = "5") @Min(value = 1, message = "The number of queries per page cannot be less than 1") private Integer pageSize = DEFAULT_PAGE_SIZE; @ApiModelProperty(value = "Ascending order", example = "true") private Boolean isAsc = true; @ApiModelProperty(value = "Sorting Fields", example = "id") private String sortBy; public int from(){ return (pageNo - 1) * pageSize; } public <T> Page<T> toMpPage(OrderItem ... orderItems) { Page<T> page = new Page<>(pageNo, pageSize); // Whether to manually specify the sorting method if (orderItems != null && > 0) { for (OrderItem orderItem : orderItems) { (orderItem); } return page; } // Is there any sorted fields in the front end if ((sortBy)){ OrderItem orderItem = new OrderItem(); (isAsc); (sortBy); (orderItem); } return page; } public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc) { if ((sortBy)){ sortBy = defaultSortBy; = isAsc; } Page<T> page = new Page<>(pageNo, pageSize); OrderItem orderItem = new OrderItem(); (); (sortBy); (orderItem); return page; } public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() { return toMpPage(Constant.DATA_FIELD_NAME_CREATE_TIME, false); } }
Design Advantages
- Default paging parameters, even if the front-end does not pass the page parameters, there will be no error.
-
Support sorting, can be passed according to the front end
sortBy
andisAsc
Sort. -
Compatible with MyBatis-Plus, directly convert to
Page<T>
, reduce duplicate code.
How to use
In actual development, we can call it at the Service layertoMpPage()
Method,PageQuery
Convert to MyBatis-PlusPage<T>
Object.
public Page<User> getUserList(PageQuery query) { Page<User> page = (); return (page, new QueryWrapper<>()); }
The art of parameter verification: from basic verification to deep defense
Why is parameter verification the first line of defense for system security?
In actual development, we often encounter such problems:
- User enters mobile phone number as "1381234abcd"
- Negative order amount
- Illegal value is passed in the status field
- The interface is attacked by maliciously constructed exception parameters
Parameter verificationLike the system guard, responsible for:
- Intercept more than 80% of conventional attacks
- Ensure the effectiveness of business data
- Improve code readability and robustness
- Reduce the verification pressure of downstream services
The core arsenal of JSR 380 specifications
Basic verification practice
@PostMapping("/create") public Result createCoupon(@Valid @RequestBody CouponFormDTO dto) { // Business logic} @Data public class CouponFormDTO { @NotNull(message = "Coupon type cannot be empty") private Integer couponType; @Range(min=1, max=10, message="The number of limited numbers exceeds the range") private Integer limitCount; @EnumValid(enumeration = {0,1}, message="Illegal way of receiving") private ReceiveEnums receiveType; }
Common annotation matrix:
annotation | Applicable Type | Applicable scenarios |
---|---|---|
@NotNull | Any object | Make sure the field cannot be empty |
@NotBlank | String | Make sure the string cannot be empty |
@NotEmpty | Collection/array | Make sure the list has data |
@Size | String/Collection | Limit length or number of elements |
@Min/@Max | Numerical type | Limit minimum/maximum value |
@Pattern | String | Regular expression verification |
String | Email format verification | |
@Future | Date | Time must be future time |
@Past | Date | Time must be the past time |
@Digits | Numerical type | Limit integer and decimal places |
Deep analysis parameter verification principle
JSR 380 verification process
- HTTP requests enter the Controller layer, bind parameters to DTO object.
-
**@Valid**
Trigger verification mechanism, call Hibernate Validator. - Execute verification logic, iterate through the DTO field and check the annotation rules.
-
Verification failed thrown
**MethodArgumentNotValidException**
。 - Global exception handler catches exceptions, encapsulate and return an error message.
@Valid vs. @Validated Difference
characteristic | @Valid | @Validated |
---|---|---|
Range of action | Single DTO | DTO + Group Verification |
Grouping support | Not supported | support |
Applicable scenarios | Basic verification | Complex business scenarios |
@PostMapping("/update") public Result update(@Validated() @RequestBody UserDTO userDTO) { // Business logic processing}
Black technology for custom enumeration verification
The hidden pain of database design
When designing databases, we usually use a certain number to represent a certain state, such as:
CREATE TABLE coupon ( status TINYINT COMMENT '0-not activated 1-effective 2-expired' )
Traditional verification methods:
if (!(0,1,2).contains(status)) { throw new IllegalArgumentException(); }
defect:
- Verification logic dispersion
- Poor maintenance
- Cannot be reused
Custom annotation solutions
Define enumeration verification annotation:
@Target() @Retention() @Constraint(validatedBy = ) public @interface EnumValid { int[] value() default {}; String message() default "Illegal enum value"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
Implement verification logic:
public class EnumValidator implements ConstraintValidator<EnumValid, Integer> { private Set<Integer> allowedValues = new HashSet<>(); @Override public void initialize(EnumValid constraintAnnotation) { (()) .forEach(allowedValues::add); } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { if (value == null) return true; return (value); } }
In-depth analysis of the principle
ConstraintValidator life cycle:
- Initialization: Read the annotation configuration
- During verification: Execute isValid method
- Result processing: Returns the boolean value
Key points of implementation of JSR 380 specification:
- Verifier discovery mechanism: SPI loading
- Cascade verification: Supports object nested verification
- Group verification: Implement verification rules for different scenarios
The ultimate solution for complex verification
Sometimes, relying solely on our verification is more complicated, and we may need to write the verification logic ourselves.
We can help us achieve it through custom annotations + AOP
/** * After implementation, if the interface implements this interface when accessing the interface * Will be checked automatically by the self-interface **/ public interface Checker<T> { /** * Used to implement data logic that cannot be verified by validation */ default void check(){ } default void check(T data){ } }
Example of usage
Data @ApiModel(description = "chapter") public class CataSaveDTO implements Checker { @ApiModelProperty("Chapter, section, practice id") private Long id; @ApiModelProperty("Catalog Type 1: Chapter 2: Section 3: Test") @NotNull(message = "") private Integer type; @ApiModelProperty("Chapter Practice Name") private String name; @ApiModelProperty("Sorting chapters, chapters must be passed on, and subsections and exercises do not need to be passed on.") private Integer index; @ApiModelProperty("Subsection or exercise in the current chapter") @Size(min = 1, message = "No empty chapters") private List<CataSaveDTO> sections; @Override public void check() { //The name is empty check if(type == && (name)) { throw new BadRequestException(.COURSE_CATAS_SAVE_NAME_NULL); }else if((name)){ throw new BadRequestException(.COURSE_CATAS_SAVE_NAME_NULL2); } //Name length issue if (type == && () > 30){ throw new BadRequestException(.COURSE_CATAS_SAVE_NAME_SIZE); }else if(() > 30) { throw new BadRequestException(.COURSE_CATAS_SAVE_NAME_SIZE2); } if((sections)){ throw new BadRequestException("No empty chapters"); } } }
Interface method parameter verification device
/** * Interface method parameter verification device **/ @Retention() @Target() public @interface ParamChecker { }
Define a facet class
@Aspect @Slf4j @SuppressWarnings("all") public class CheckerAspect { @Before("@annotation(paramChecker)") public void before(JoinPoint joinPoint, ParamChecker paramChecker) { Object[] args = (); if((args)){ //Transaction method parameters, whether the parameters implement the Checker interface for (Object arg : args){ if(arg instanceof Checker) { //Calling the check method to verify the business logic ((Checker)arg).check(); }else if(arg instanceof List){ //If the parameters are a set, check it ((List) arg); } } } } }
Tools and methods
/** * Set verification logic * * @param data Collection to be verified * @param checker * @param <T> Collection element type */ public static <T> void check(List<T> data, Checker<T> checker){ if(data == null){ return; } for (T t : data){ (t); } } /** * Set verification logic * * @param data Collection to be verified * @param <T> Collection element type */ public static <T extends Checker<T>> void check(List<T> data){ if(data == null){ return; } for (T t : data){ (); } }
Annotation usage
@PostMapping("baseInfo/save") @ApiOperation("Save basic course information") @ParamChecker //Check fields that are not business restricted public CourseSaveVO save(@RequestBody @Validated() CourseBaseInfoSaveDTO courseBaseInfoSaveDTO) { return (courseBaseInfoSaveDTO); }
Note: The section class is not included in the IOC container management. If it is a single project and the component annotation is enough. If it is a multi-module project, use the automatic assembly function.
Summarize
This is the end of this article about detailed explanations of pagination and parameter verification in Java Web development. For more related Java Web pagination and parameter verification content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!