cuốn sách gpt4 ai đã làm

Sử dụng @Validated và @Valid với trình xác nhận mùa xuân

In lại Tác giả: Taklimakan Thời gian cập nhật: 2023-11-03 04:44:24 28 4
mua khóa gpt4 Nike

Tôi có một java đậu để gửi tin nhắn JSON tới mùa xuân @RestController và tôi đã thiết lập và sử dụng xác thực đậu @Có hiệu lực Chạy tuyệt vời. Nhưng tôi muốn chuyển sang Protobuf/Thrift và tránh xa REST. Nó là một API nội bộ và nhiều công ty lớn đã loại bỏ REST trong nội bộ. Điều này thực sự có nghĩa là tôi không còn kiểm soát các đối tượng thông báo nữa - chúng được tạo ra từ bên ngoài. Tôi không thể chú thích chúng nữa.

Vì vậy, bây giờ xác nhận của tôi phải được lập trình. Tôi nên làm gì? Tôi đã viết một Trình xác thực Và nó hoạt động rất tốt. Nhưng nó không sử dụng khá @Có hiệu lực Ghi chú. Tôi phải làm như sau:

@Dịch vụ
public StuffEndpoint triển khai StuffThriftDef.Iface {

@Autowired
MyValidator riêng myValidator;

public void things(MyMessage msg) ném BindException {
Lỗi BindingResult = new BeanPropertyBindingResult(msg, msg.getClass().getName());
lỗi = myValidator.validate(msg);
if (errors.hasErrors()) {
ném BindException mới (lỗi);
} khác {
doRealWork();
}
}
}

Cái này bốc mùi quá. Tôi phải làm điều này bằng mọi cách. Bây giờ tôi có thể đặt rất nhiều thứ này vào một cú ném Ngoại lệ liên kết để bạn có thể thêm một dòng mã vào mỗi phương thức. Nhưng nó vẫn chưa tuyệt vời.

Điều tôi muốn là thấy nó trông như thế này:

@Dịch vụ
@Validated
public StuffEndpoint triển khai StuffThriftDef.Iface {

public void things(@Valid MyMessage msg) {
doRealWork();
}
}

Vẫn nhận được kết quả tương tự. Hãy nhớ rằng, đậu của tôi không có chú thích. Có, tôi biết tôi có thể sử dụng phương pháp @InitBinder Ghi chú. Nhưng điều này chỉ hoạt động đối với các yêu cầu mạng.

Tôi không ngại đặt đúng Trình xác thực Đưa lớp này vào, nhưng tôi muốn ValidatorFactory của mình dựa trên hỗ trợ() Phương pháp trích xuất trình xác nhận chính xác.

Điều này có thể thực hiện được không? Có cách nào để định cấu hình xác thực Bean để thực sự sử dụng xác thực Spring không? Tôi có phải chiếm đoạt một khía cạnh ở đâu đó không? xâm lược LocalValidatorFactory hoặc Phương thứcXác thựcPostProcessor?

Cảm ơn.

câu trả lời hay nhất

Việc kết hợp xác thực Spring và các ràng buộc JSR-303 là một vấn đề rất phức tạp. Và không có cách "sẵn sàng để sử dụng". Sự bất tiện chính là việc xác thực Spring sử dụng Ràng buộcKết quả, trong khi JSR-303 sử dụng Ràng buộcValidatorContext như kết quả xác minh.

Bạn có thể thử tạo công cụ xác thực của riêng mình bằng Spring AOP. Hãy suy nghĩ về những gì chúng ta cần làm về điều này. Đầu tiên, hãy khai báo các phần phụ thuộc AOP (nếu bạn chưa có):


org.springframework
spring-aop
4.2.4.RELEASE


org.aspectj
khía cạnh
1.8.8
thời gian chạy


org.aspectj
khía cạnhjweaver
1.8.8

tôi đang sử dụng 4.2.4.PHÁT HÀNH phiên bản Spring, nhưng tất nhiên bạn có thể sử dụng phiên bản của riêng mình. Cần có AspectJ để sử dụng chú thích khía cạnh. Tiếp theo, chúng ta phải tạo một sổ đăng ký xác thực đơn giản:

lớp công khai CustomValidatorRegistry {

Danh sách riêng validatorList = new ArrayList<>();

public void addValidator(Trình xác thực trình xác thực){
validatorList.add(trình xác nhận);
}

Danh sách công khai getValidatorsForObject(Object o) {
List result = new ArrayList<>();
for(Trình xác thực trình xác thực: validatorList){
if(validator.supports(o.getClass())){
result.add(trình xác thực);
}
}
return result;
}
}

Như bạn có thể thấy, đây là một lớp rất đơn giản cho phép chúng ta tìm trình xác thực của một đối tượng. Bây giờ hãy tạo chú thích, đây sẽ là phương thức được gắn thẻ cần được xác thực:

gói com.mydomain.validation;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
công khai @interface CustomValidation {
}

Bởi vì tiêu chuẩnNgoại lệ ràng buộc lớp học thì khôngNgoại lệ thời gian chạy, chúng ta không thể sử dụng nó trong các phương thức ghi đè. Điều này có nghĩa là chúng ta cần xác định ngoại lệ của riêng mình:

lớp công khai CustomValidatorException mở rộng RuntimeException {

Ràng buộc BindingResult riêng tưKết quả;

public CustomValidatorException(BindingResult bindResult){
this.bindResult = ràng buộcResult;
}

BindingResult công khai getBindingResult() {
trả lại kết quả ràng buộc;
}
}

Bây giờ chúng ta đã sẵn sàng tạo ra một khía cạnh sẽ thực hiện hầu hết công việc. Các khía cạnh sẽ được thực thi trước các phương thức sử dụng Xác thực tùy chỉnh Dấu nhận xét:

@Diện mạo
@Thành phần
lớp công khai CustomValidatingAspect {

@Autowired
sổ đăng ký CustomValidatorRegistry riêng tư // khía cạnh sẽ sử dụng sổ đăng ký trình xác thực của chúng tôi;


@Before(value = "execution(public * *(..)) && chú thích(com.mydomain.validation.CustomValidation)")
public void doBefore(Điểm tham gia){
Chú thích[][] paramAnnotations =
((MethodSignature)point.getSignature()).getMethod().getParameterAnnotations();
for(int i=0; i
for(Chú thích chú thích: paramAnnotations[i]){
//kiểm tra org.springframework.validation.annotation.Validated tiêu chuẩn
if(annotation.annotationType() == Validated.class){
Đối tượng arg = point.getArgs()[i];
if(arg==null) tiếp tục;
xác thực (arg);
}
}
}
}

xác thực khoảng trống riêng tư (Object arg) {
List validatorList = register.getValidatorsForObject(arg);
for(Trình xác thực trình xác thực: validatorList){
Lỗi BindingResult = new BeanPropertyBindingResult(arg, arg.getClass().getSimpleName());
validator.validate(arg, error);
if(errors.hasErrors()){
ném CustomValidatorException mới (lỗi);
}
}
}
}

thực thi (công khai * * (..)) && @annotation (com.springapp.mvc.validators.CustomValidation) Có nghĩa là, khía cạnh này sẽ áp dụng cho bất kỳ phương thức công khai nào của một Bean được đánh dấu bằng @CustomValidation Ghi chú. Cũng lưu ý rằng để đánh dấu các tham số đã được xác thực, chúng tôi sử dụng tiêu chuẩn org.springframework.validation.annotation.Validated Ghi chú. Nhưng tất nhiên chúng ta có thể tùy chỉnh. Tôi nghĩ mã này đơn giản và không cần bất kỳ nhận xét nào. Thêm mã cho trình xác thực ví dụ:

lớp công khai PersonValidator triển khai Trình xác thực {
@Ghi đè
hỗ trợ boolean công khai(Class aClass) {
trả về aClass==Person.class;
}

@Ghi đè
public void valid(Object o, Lỗi lỗi) {
Người người = (Người)o;
if(person.getAge()<=0){
error.rejectValue("tuổi", "Tuổi quá nhỏ");
}
}
}

Bây giờ chúng ta đã điều chỉnh cấu hình và sẵn sàng sử dụng:

@Cấu hình
@ComponentScan(basePackages = "com.mydomain")
@EnableAspectJAutoProxy(proxyTargetClass = true)
lớp công khai AppConfig{

.....

@Bean
công khai CustomValidatorRegistry validatorRegistry(){
Đăng ký CustomValidatorRegistry = new CustomValidatorRegistry();
register.addValidator(new PersonValidator());
trả lại sổ đăng ký;
}
}

Xin lưu ý rằngproxyTargetClassĐÚNG VẬY Bởi vì chúng ta sẽ sử dụng cglib đại lý lớp.


Ví dụ về phương thức đích trong lớp dịch vụ:

@Dịch vụ
lớp công khai PersonService{

@CustomValidation
public void savePerson(@Người được xác thực){
....
}

}

由于 @CustomValidation Các khía cạnh chú thích sẽ được áp dụng và do @Validated 注释 người sẽ được xác minh. Và một ví dụ về việc sử dụng dịch vụ trong Bộ điều khiển (hoặc bất kỳ lớp nào khác):

@Controller
lớp công khai PersonConroller{

@Autowired
dịch vụ PersonService riêng tư;

public String savePerson(@ModelAttribution Person Person, ModelMap model){
try{
service.savePerson(người);
}bắt(CustomValidatorException e){
model.addAttribution ("lỗi", e.getBindingResult());
trả về "tên xem";
}
trả về "tên xem";
}

}

Hãy nhớ rằng nếu bạn bắt đầu từ NgườiDịch vụ Được gọi trong phương thức lớp @CustomValidation, xác minh sẽ không hoạt động. Bởi vì nó sẽ gọi phương thức của lớp gốc chứ không phải proxy. Điều này có nghĩa là nếu bạn muốn quá trình xác thực hoạt động bình thường (ví dụ:@Transactional hoạt động theo cách tương tự), bạn chỉ có thể gọi phương thức này từ bên ngoài lớp (từ các lớp khác).

Xin lỗi vì một bài viết dài như vậy. Câu trả lời của tôi không liên quan gì đến "cách khai báo đơn giản", có thể bạn không cần. Nhưng tôi tò mò về việc giải quyết vấn đề này.

Về java - sử dụng @Validated và @Valid với trình xác nhận mùa xuân, chúng tôi đã tìm thấy một câu hỏi tương tự trên Stack Overflow: https://stackoverflow.com/questions/36089676/

28 4 0
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress