【问题标题】:Spring-boot not supported in 'DELETE','PUT' and |'GET' item by id|'DELETE'、'PUT' 和 |'GET' item by id| 中不支持 Spring-boot
【发布时间】:2021-08-09 12:13:35
【问题描述】:

我正在 Spring-boot 架构的帮助下使用 RESTful Web 服务测试一个简单的后端。现在我已经完成了后端,但是我无法使用get item by id 访问DELETEPUTGET 方法(其他http 方法工作-GET allPOST

用户控制器类

package com.pali.palindromebackend.api;

import com.pali.palindromebackend.business.custom.UserBO;
import com.pali.palindromebackend.business.util.EntityDTOMapper;
import com.pali.palindromebackend.dto.UserDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.sql.SQLException;
import java.util.List;
import java.util.NoSuchElementException;
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    @Autowired
    private UserBO bo;

    @Autowired
    private EntityDTOMapper mapper;

    public UserController() throws SQLException{

    }

    @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<List<UserDTO>> getAllUsers() throws Exception {
        System.out.println("get");
        return new ResponseEntity<List<UserDTO>>(bo.getAllUsers(), HttpStatus.OK);
    }

    @GetMapping(value = "/{userId}", produces = MediaType.APPLICATION_JSON_VALUE )
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<Object> getUserById(@PathVariable Integer userId) throws Exception {
        System.out.println("One");
        try {
            return new ResponseEntity<>(bo.getUser(userId), HttpStatus.OK);
        } catch (NoSuchElementException e) {
            return new ResponseEntity<>("No user found !!", HttpStatus.NOT_FOUND);
        } catch (Exception e) {
            return new ResponseEntity<>("Something went wrong !!", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping(
            produces = MediaType.APPLICATION_JSON_VALUE,
            consumes = MediaType.APPLICATION_JSON_VALUE
    )
    @ResponseBody
    public ResponseEntity<Object> saveUser(@Valid @RequestBody UserDTO dto) throws Exception {
        System.out.println(mapper.getUser(dto));
        try {
            bo.saveUser(dto);
            return new ResponseEntity<>(dto, HttpStatus.CREATED);
        } catch (Exception e) {
            return new ResponseEntity<>("Something went wrong", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    @DeleteMapping("/{userId}")
    public ResponseEntity<Object> deleteUser(@PathVariable Integer userId) throws Exception {
        try {
            bo.getUser(userId);
            bo.deleteUser(userId);
            return new ResponseEntity<>("Successfully deleted the user !!", HttpStatus.CREATED);
        } catch (NoSuchElementException e) {
            return new ResponseEntity<>("No user is found !!", HttpStatus.NOT_FOUND);
        } catch (Exception e) {
            return new ResponseEntity<>("Something went wrong!!", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    @PutMapping(
            value = "/{userId}",
            produces = MediaType.APPLICATION_JSON_VALUE,
            consumes = MediaType.APPLICATION_JSON_VALUE
    )
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<Object> updateUser(@Valid @RequestBody UserDTO dto, @PathVariable Integer userId)
            throws Exception {
        if (dto.getId() != userId) {
            return new ResponseEntity<>("Mismatch userId !!", HttpStatus.BAD_REQUEST);
        }
        try {
            bo.getUser(userId);
            bo.updateUser(dto);
            return new ResponseEntity<>(dto, HttpStatus.CREATED);
        } catch (NoSuchElementException e) {
            return new ResponseEntity<>("No user is found !!", HttpStatus.NOT_FOUND);
        } catch (Exception e) {
            return new ResponseEntity<>("Something went wrong !!", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

AppInitializer 类

import com.pali.palindromebackend.util.LogConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PalindromeBackendApplication {

    public static void main(String[] args) {
        LogConfig.initLogging();
        SpringApplication.run(PalindromeBackendApplication.class, args);
    }

}

安全配置

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;
    @Autowired
    private JWTRequestFilter jwtRequestFilter;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                .antMatchers("/api/v1/authenticate").permitAll()
                .antMatchers("/api/v1/users").permitAll()
                .anyRequest().authenticated()
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}

MyUserDetailsS​​ervice

@Service
public class MyUserDetailsService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return new User("admin","admin",new ArrayList<>());
    }
}

JWTRequestFilter

@Component
public class JWTRequestFilter extends OncePerRequestFilter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private JWTUtil jwtUtil;
    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
        final String authorizationHeader = req.getHeader("Authorization");

        String userName = null;
        String jwt = null;

        if (authorizationHeader != null && authorizationHeader.startsWith("Bearer")){
            jwt = authorizationHeader.substring(7);
            userName = jwtUtil.extractUsername(jwt);
        }
        if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null){
            UserDetails userDetails = this.myUserDetailsService.loadUserByUsername(userName);
            if(jwtUtil.validateToken(jwt,userDetails)){
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities()
                );
                usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
        chain.doFilter(req,res);
    }
}

CORS 过滤器

import org.springframework.stereotype.Component;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CORSFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        response.setHeader("Access-Control-Allow-Origin", "http://localhost:4200");
        response.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTION");
        response.setHeader("Access-Control-Allow-Headers", "Content-type,Authorization");
        super.doFilter(request, response, chain);
    }
}

我发送了GET http://localhost:8080/api/v1/users and POST http://localhost:8080/api/v1/usersheaders with{'name':'Charls','password':'asd123'}`(JSON 类型)并且那些有效.

但是 GET http://localhost:8080/api/v1/courses/3 - 通过 id 、DELETE localhost:8080/api/v1/users/3PUT localhost:8080/api/v1/users/3JSON head {"name": "Samwise Gamgee", "duration": "ring bearer"} -user update 获取项目。这些方法不起作用 :(

2021-05-20 12:55:01.798  WARN 15187 --- [nio-8080-exec-2] o.s.web.servlet.PageNotFound             : Request method 'PUT' not supported
2021-05-20 12:55:32.746  WARN 15187 --- [nio-8080-exec-3] o.s.web.servlet.PageNotFound             : Request method 'DELETE' not supported

在这里,当我生成请求时,即使任何方法(PUT、DELETE、GET item by id)都不起作用。所以这个问题也不例外:(

【问题讨论】:

  • 你启用了spring security吗?
  • @pL4Gu33 请再次检查我已经添加了相关类

标签: java spring spring-boot rest spring-data-jpa


【解决方案1】:

您需要为它们设置允许的方法。您可以为此添加一个 bean。

    @Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/**")
                    .allowedOrigins("*")
                    .allowedMethods("GET", "PUT", "POST", "PATCH", "DELETE", "OPTIONS");
        }
    };
}

注意:这是允许所有来源的代码。您需要根据需要进行配置。

【讨论】:

  • 是的,兄弟,我将这些相关内容添加为 CORS 过滤器。我在问题的末尾添加了它们
【解决方案2】:

如下更改你的控制器方法

@GetMapping(value = "/{userId}", 
produces = MediaType.APPLICATION_JSON_VALUE )
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<Object> getUserById(@PathVariable("userId") Integer userId) throws Exception {
        System.out.println("One");
        try {
            return new ResponseEntity<>(bo.getUser(userId), HttpStatus.OK);
        } catch (NoSuchElementException e) {
            return new ResponseEntity<>("No user found !!", HttpStatus.NOT_FOUND);
        } catch (Exception e) {
            return new ResponseEntity<>("Something went wrong !!", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

@ResponseStatus(HttpStatus.CREATED)
    @ResponseBody
    @DeleteMapping("/{userId}")
    public ResponseEntity<Object> deleteUser(@PathVariable("userId") Integer userId) throws Exception {
        try {
            bo.getUser(userId);
            bo.deleteUser(userId);
            return new ResponseEntity<>("Successfully deleted the user !!", HttpStatus.CREATED);
        } catch (NoSuchElementException e) {
            return new ResponseEntity<>("No user is found !!", HttpStatus.NOT_FOUND);
        } catch (Exception e) {
            return new ResponseEntity<>("Something went wrong!!", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


@PutMapping(
            value = "/{userId}",
            produces = MediaType.APPLICATION_JSON_VALUE,
            consumes = MediaType.APPLICATION_JSON_VALUE
    )
    @ResponseStatus(HttpStatus.OK)
    @ResponseBody
    public ResponseEntity<Object> updateUser(@Valid @RequestBody UserDTO dto, @PathVariable("userId") Integer userId)
            throws Exception {
        if (dto.getId() != userId) {
            return new ResponseEntity<>("Mismatch userId !!", HttpStatus.BAD_REQUEST);
        }
        try {
            bo.getUser(userId);
            bo.updateUser(dto);
            return new ResponseEntity<>(dto, HttpStatus.CREATED);
        } catch (NoSuchElementException e) {
            return new ResponseEntity<>("No user is found !!", HttpStatus.NOT_FOUND);
        } catch (Exception e) {
            return new ResponseEntity<>("Something went wrong !!", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
}

如果仍然无法调用您的 GET、PUT、DELETE 方法,请检查您的业务逻辑

【讨论】:

    【解决方案3】:

    是的,感谢所有回答我问题的人,我找到了问题的根源:/

    • SecurityConfig 中,我只允许以 /api/v1/authenticate/api/v1/users 结尾的请求.
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().disable().authorizeRequests()
                    .antMatchers("/api/v1/authenticate").permitAll()
                    .antMatchers("/api/v1/users").permitAll()
                    .anyRequest().authenticated()
                    .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
            http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
        }
    
    • 所以我无法传递像 localhost:8080/api/v1/users/3 这样的 DELETE 请求,因为它包含的“/3”比“/api/v1/users”多; SecurityConfig 阻止它。
    • 所以这就是我的问题发生的情况(未授予对安全过滤器的访问权限以传递此类请求)
    • 如果我们想获得通过此类请求的访问权限,我们应该在 securityConfig 中提及相关路径

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-20
      • 2014-05-15
      • 1970-01-01
      • 2019-11-07
      • 2015-06-24
      • 2020-01-29
      • 1970-01-01
      • 2020-04-11
      相关资源
      最近更新 更多