【问题标题】:Inject request attribute from request to spring controller methods将请求属性从请求注入到弹簧控制器方法
【发布时间】:2016-08-18 16:58:39
【问题描述】:

我有一些 spring @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);
}

但仍然需要我在每个方法中添加该参数。 这个参数可以以某种方式注入每个方法吗?

【问题讨论】:

  • 你读过the reference guide吗?您不需要方面,因为它是开箱即用的......不要让事情变得比需要的更复杂。
  • 我似乎无法理解它是如何开箱即用的?我需要将这段代码放在我拥有的每个方法上,我想避免它。
  • 如果是 JWT 那么我强烈建议不要设置属性与请求正确集成并使用主体。这样,您可以在请求上执行 getPrincipal 或简单地将 Principal 添加到方法签名中。如果您使用 Spring Security 解码 JWT,您将免费获得此支持(您需要配置)。

标签: java spring inject


【解决方案1】:

如果您真的想了解属性,那么您应该查看 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);
}

【讨论】:

  • @Header 属性对我不起作用,因为数据位于请求属性中。我得到这样的用户的原因是我使用 jwt,并且在我的控制器之前有一个过滤器,它从令牌中获取用户并将其放在请求中。
  • 我需要的是@Value("#{request.getAttribute('subject')}" 但这仍然需要对每种方法进行重复。我已经更新了问题,感谢您的帮助跨度>
  • 您是否先尝试了@RequestAttribute? Spring 应该直接为您处理此问题,而无需求助于拼写。
【解决方案2】:

您可以使用Filter 填充存储该属性的ThreadLocal&lt;String&gt; 变量:

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());
  }

您还必须在 web.xml 文件中注册 Filter

<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&lt;Map&lt;String, String&gt;&gt; 变量。

【讨论】:

    【解决方案3】:

    只需在其余部分添加@ResuestAttribute contorller

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

    你的属性......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-18
      • 2021-06-18
      • 2013-02-08
      • 1970-01-01
      • 2018-07-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多