У меня есть несколько весенних методов @RestControllers, которые я хотел бы ввести со значением, которое приходит с каждым запросом в качестве атрибута запроса (содержащего пользователя), например:

@RestController
@RequestMapping("/api/jobs")
public class JobsController {
     // Option 1 get user from request attribute as prop somehow
     private String userId = "user1";

    // Option 2 inject into method using aspect or something else
    @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Jobs>> getJobs() throws ResourceNotFoundException {
       // currentUser is injected 
       this.getJobs(currentUser);
}

Я знаю, что могу это сделать:

@RestController
@RequestMapping("/api/jobs")
public class JobsController {

    @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Jobs>> getJobs(HttpServletRequest request) throws ResourceNotFoundException { 
       String currentUser = null;
       if (request.getAttribute("subject") != null) {
           currentUser = request.getAttribute("subject").toString();
       }
       this.getJobs(currentUser);
}

Но для этого мне потребуется добавить этот код в каждый метод в моей программе, что, как мне кажется, является действительно плохой практикой.
Есть ли способ добиться того, чего я хочу?

Если ответ требует аспекта, пример кода будет очень признателен, так как я только читал об этом, но никогда не делал что-то с аспектом.

Обновить
Предложенный мной код можно упростить, используя это:

@RestController
@RequestMapping("/api/jobs")
public class JobsController {

    @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<List<Jobs>> getJobs(@Value("#{request.getAttribute('subject')}" String currentUser) throws ResourceNotFoundException { 
       this.getJobs(currentUser);
}

Но все же требуйте, чтобы я добавлял этот параметр в каждый метод. Можно ли каким-то образом ввести этот параметр в каждый метод?

2
Cony 25 Апр 2016 в 13:41

3 ответа

Лучший ответ

Вы можете использовать Filter для заполнения переменной ThreadLocal<String>, в которой хранится этот атрибут:

public class MyFilter implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {}

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    ContextHolder.setSubject(request.getAttribute('subject'));
    chain.doFilter(request, response);
  }

  @Override
  public void destroy() {
    ContextHolder.removeSubject();
  }
}


public class ContextHolder {

  private static final ThreadLocal<String> SUBJECT = new ThreadLocal<String>() {
    @Override
    protected String initialValue() {
      return "empty";
    }
  };

  public static void setSubject(String subject) {
    SUBJECT.set(subject);
  }

  public static String getSubject() {
    return SUBJECT.get();
  }

  public static void removeSubject() {
    SUBJECT.remove();
  }
}

Фильтр будет настроен на перехват всех запросов и заполнение переменной SUBJECT. Используя ThreadLocal, вы убедитесь, что каждый поток имеет собственное значение subject. Теперь вы можете получить это значение в любом месте вашего приложения, вызвав ContextHolder.getSubject():

  @RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
  public ResponseEntity<List<Jobs>> getJobs(HttpServletRequest request) throws ResourceNotFoundException { 
    this.getJobs(ContextHolder.getSubject());
  }

Вам также необходимо зарегистрировать Filter в файле web.xml:

<filter>
    <filter-name>MyFilter</filter-name>
    <filter-class>com.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Если у вас несколько атрибутов, вы можете использовать вместо них переменную ThreadLocal<Map<String, String>>.

3
carcaret 26 Апр 2016 в 11:45

Просто добавьте @ResuestAttribute в свой остальной контроллер

@RestController
@RequestMapping(path="/yourpath")

@RequestMapping(method = RequestMethod.GET)
    public ResponseEntity getAll(
            @RequestAttribute(value = "yourAttribute") Object 

YourAttribute ......

0
Dave 28 Июн 2017 в 09:43

Если вы действительно хотите узнать об атрибутах, вам следует проверить spring @ RequestParam аннотация. Вы бы использовали это так:

@RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Jobs>> getJobs(@RequestParam("subject") String currentUser) throws ResourceNotFoundException { 
   this.getJobs(currentUser);
}
0
Software Engineer 26 Апр 2016 в 09:39