简体   繁体   中英

Message Localisation in Spring Boot

I have a number of springboot application. There are many modules, and they're assembled in different ways, depending on the situation. In it, I have a number of Exceptions, some of which will be visible to the UI. These exceptions should be localised.

basically

 spring-boot-fat-jar
     module-user.jar
          resources
               message.properties
          classes
               UserService.class
               UserConflictException.class
     module-auth.jar
          resources
               message.properties
          classes
               NotAuthorizedException.class

I do have specific exceptions (with a message such as "You cannot delete user X, because they are still assigned as manager of group Y"), which are easy to localise - use basically throw:

 throw new UserConflictException(
     msgSrc,
     "USER.DELETE.CONFLICT_HAS_GROUPS"
 );

This works, because the properties file the message is stored in and the code that throws the exception are (in this case) in the same location (ie the same jar file within the spring boot fat jar).

However, if I want to throw a "NotAuthorizedException", which basically just says "you're not authorized" .... then that class is visible, but the message is not. Obviously, I wouldn't want to have to repeat that message in every message.properties file.

Instead, I would like to have all messages that are on the classpath accumulated. All message codes are hierarchical/namespaced so there's no risk of collision, really.

Obviously, I could do a classpath scan an collect all those messages, then instantiate my own message source from that ... but that is most likely not the the correct "spring-booty" way of doing this. There must be a better way. Can you help me find it? Maybe I am just missing something really obvious?

.rm

I have a solution that works for now and is only slightly ugly - I actually do a classpath scan (using fast-classpath-scanner) and add the messages found to a

ReloadableResourceBundleMessageSource 

like this:

@Bean
public MessageSource globalMessageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    FastClasspathScanner fcs = new FastClasspathScanner();
    fcs.matchFilenamePattern("i18n/.*/messages\\.properties", new FileMatchContentsProcessor() {
        @Override
        public void processMatch(String relativePath, byte[] fileContents) throws IOException {
            try {
                relativePath = relativePath.substring(0, relativePath.length()-11);
                messageSource.addBasenames(relativePath);
                log.info("found messages: "+relativePath);
            } catch (Exception e2) {
                log.error("error processing mail template: "+relativePath,e2);
            }
        }
    });
    fcs.scan();
    return messageSource;
}

given that the messages are in:

ressources/i18n/${module_name}

this does the trick. However, I am not completely convinced this is the best solution?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM