Spring Boot:使用BaseController实现CRUD时解决URL路径404问题
问题:Spring Boot 接口404异常 - /api/brands无法访问但/brands正常
我开发了一个Spring Boot应用,实现了处理所有实体CRUD操作的BaseController,同时创建了继承该基类的BrandController,以及实现CrudRepository的BrandRepository。目前遇到的问题是:访问BrandController的/api/brands等端点时会出现404错误,但访问/brands却可以正常访问。请问如何修复该问题,使端点能通过/api/实体名的形式访问?
相关代码
BrandController.java
package parc.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import parc.model.concrete.Brand; import parc.repository.BrandRepository; @RestController @RequestMapping("/api/brands") public class BrandController extends BaseController<Brand, BrandRepository> { private final BrandRepository repository; public BrandController(BrandRepository repository) { super(repository); this.repository = repository; } }
BaseController.java
package parc.controller; import org.springframework.data.repository.CrudRepository; import org.springframework.web.bind.annotation.*; import java.util.List; public class BaseController<T, R extends CrudRepository<T, Long>> { private R repository; public BaseController(R repository) { this.repository = repository; } @GetMapping("/") public List<T> getAll() { return (List<T>) repository.findAll(); } @PostMapping("/") public T create(@RequestBody T entity) { return repository.save(entity); } @GetMapping("/{id}") public T getById(@PathVariable long id) { return repository.findById(id).orElse(null); } @PutMapping("/{id}") public T update(@PathVariable long id, @RequestBody T entity) { return repository.save(entity); } @DeleteMapping("/{id}") public void delete(@PathVariable long id) { repository.deleteById(id); } }
BrandRepository.java
package parc.repository; import org.springframework.data.repository.CrudRepository; import parc.model.concrete.Brand; public interface BrandRepository extends CrudRepository<Brand, Long> { }
问题原因
- 路径拼接不匹配:BaseController中所有请求映射都带了末尾斜杠
/,和BrandController的/api/brands拼接后,实际有效路径是/api/brands/(带斜杠),但你访问的/api/brands不带斜杠,导致匹配失败。 - Spring Data REST自动暴露接口:如果你的项目引入了
spring-boot-starter-data-rest依赖,框架会自动为CrudRepository生成/brands(实体类名复数形式)的默认REST接口,这就是/brands能正常访问的原因。
修复方案
方案一:调整基类请求映射,修正路径拼接
修改BaseController中的所有请求映射,去掉末尾斜杠,改为空字符串"",这样子类的路径会和基类路径直接拼接,形成正确的接口地址:
public class BaseController<T, R extends CrudRepository<T, Long>> { private R repository; public BaseController(R repository) { this.repository = repository; } @GetMapping("") // 去掉末尾斜杠 public List<T> getAll() { return (List<T>) repository.findAll(); } @PostMapping("") // 去掉末尾斜杠 public T create(@RequestBody T entity) { return repository.save(entity); } @GetMapping("/{id}") public T getById(@PathVariable long id) { return repository.findById(id).orElse(null); } @PutMapping("/{id}") public T update(@PathVariable long id, @RequestBody T entity) { return repository.save(entity); } @DeleteMapping("/{id}") public void delete(@PathVariable long id) { repository.deleteById(id); } }
修改后,BrandController的有效接口路径为:
- GET
/api/brands(获取所有品牌) - POST
/api/brands(创建品牌) - GET
/api/brands/{id}(根据ID查询品牌) - PUT
/api/brands/{id}(更新品牌) - DELETE
/api/brands/{id}(删除品牌)
方案二:禁用Spring Data REST默认接口(可选)
如果你不需要框架自动生成的/brands接口,可以添加配置类关闭默认暴露:
import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; import org.springframework.context.annotation.Configuration; @Configuration public class RestConfig implements RepositoryRestConfigurer { @Override public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { config.disableDefaultExposure(); // 禁用默认Repository REST接口 } }
内容的提问来源于stack exchange,提问作者ayoubachak
相关产品推荐
相关产品推荐

