如何使用外部文件作为MessageSource的资源?

时间:2019-01-15 09:13:36

标签: spring-boot

我在库包中创建了验证注释类,例如@IpV4@IpV4List。这些批注返回违反验证时可以在MessageSource中使用的密钥(代码)。

message.properties文件位于common资源文件夹中,并且在注册MessageSource bean时,每个在库包中使用注释的模块都会尝试指定路径。

但是,当注释引发诸如MethodArgumentNotValidException之类的异常时,MessageSource找不到带有消息模板(注释中定义的代码)的任何消息。

我已经尝试过与该问题相关的StackOverFlow上发布的大多数方法。

  1. application.properties中的基本名称(无静态位置)
spring.messages.basename=messages/messages, file:/path/to/file
  1. @Configuration类中的基本名称(没有静态位置)
@Bean
public MessageSource messageSource(){
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("messages/messages", "file:/path/to/file");
    // some other settings...
    return messageSource;
}
  1. application.properties中的静态资源位置
spring.messages.basename=messages/messages, messages/vailidation_messages
spring.resources.static-locations=file:/path/to/parent_of_messages
  1. ```@ Configuration`类中的静态资源位置
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("file:/path/to/parent_of_messages")
    // some other settings
    ;
}

我尝试了许多其他方法,但是我无法通过调用MessageSource.getMessage()得到消息,并且发生了ConstraintViolationException

我的项目结构如下。

foo-cloud
│
├─ foo-config
│  ├─ resources
│  │  ├─ messages << message properties here
│  │  │  ├─ validation_messages.properties
│  │  │  ├─ validation_messages_en.properties
│  │  │  ├─ validation_messages_ja.properties
│  │  │  └─ validation_messages_ko.properties
│  │  └─ ...
│  └─ ...
├─ foo-auth
├─ ...
├─ foo-gateway
│
├─ foo-resource
│  ├─ ...
│  ├─ foo-application << module to register Bean for MessageSource here
│  └─ ...
│
├─ foo-library
│  ├─ ...
│  └─ util-lib << annotation for validation here
│ 
└─ foo-web
   └─ ...
  • application-dev.properties(当前,edited
spring.messages.basename=messages/messages, messages/validation_messages # <- how to fix?
spring.messages.encoding=UTF-8
# spring.resources.static-locations=file:../../foo-config/resources #not used anymore
  • 库包中的IPV4类
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;

@Documented
@Constraint(validatedBy = {})
@Target({ FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Pattern(regexp = IpV4.PATTERN, message = IpV4.NOT_MATCH)
@NotEmpty(message = IpV4.NOT_EMPTY)
public @interface IpV4 {

    String  PATTERN     = "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
    String  NOT_EMPTY   = "validation.ip-v4.not_empty";
    String  NOT_MATCH   = "validation.ip-v4.not_match";

    String message() default "invalid ip format";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}
  • ExceptionHandler类
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> validationExceptionCaught(
        MethodArgumentNotValidException e) {
    return Collections.singletonMap("message", messageSource.getMessage(
            e.getBindingResult().getFieldError().getDefaultMessage()));
}

/**
 * for debugging
 */
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> validationExceptionCaught(
        MethodArgumentTypeMismatchException e) {
    return Collections.singletonMap("message", e.getMessage());
}

@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> validationExceptionCaught(
        ConstraintViolationException e) {
    return Collections.singletonMap("message",
            messageSource.getMessage(
                    e.getConstraintViolations().stream().findFirst()
                            .map(ConstraintViolation::getMessageTemplate)
                            .orElse(e.getMessage())));
}
  • DTO类使用@ IpV4注释
import foo.bar.lib.common.validator.IpV4;
import lombok.Data;

@Data
public class BarRequest {
    @IpV4
    private String startIp;
    @IpV4
    private String endIp;
    private String description;
}

如何使用外部文件作为MessageSource共享验证消息的资源?

恐怕我的英语能力不足以沟通。

1 个答案:

答案 0 :(得分:0)

最后,我解决了这个问题。

问题是尝试各种方法时配置文件扭曲或文件路径中有错字。

我从MessageSource文件中删除了与application.properties相关的所有属性,并将MessageSource类中的@Configuration bean注册为以下来源。

@Bean
public MessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setBasenames("classpath:messages/messages",
            "file:D:/foo-cloud/foo-config/resources/messages_validation");
    messageSource.setCacheSeconds(600);
    messageSource.setUseCodeAsDefaultMessage(true);
    messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
    return messageSource;
}

感谢M.Deinum为我提供帮助。