【问题标题】:@RequestMapping doesn't map correctly@RequestMapping 没有正确映射
【发布时间】:2020-09-23 05:57:06
【问题描述】:

我的问题是,当我在 CommentController 类上方使用注释 @RequestMapping("/adverts/{id}") 时,我可以同时使用(即)localhost:8080/adverts/1/commentslocalhost:8080/comments 来访问此类。如何禁用到达localhost:8080/comments?谢谢。

@RestController
class CommentController {

    private final CommentRepository commentRepository;
    private final AdvertRepository advertRepository;
    private final CommentModelAssembler assembler;

    CommentController(CommentRepository commentRepository, AdvertRepository advertRepository, CommentModelAssembler assembler) {
        this.commentRepository = commentRepository;
        this.advertRepository = advertRepository;
        this.assembler = assembler;
    }

    @GetMapping("/adverts/{advertId}/comments")
    CollectionModel<EntityModel<Comment>> all() {
        List<EntityModel<Comment>> comments =
                commentRepository.findAll().stream()
                        .map(assembler::toModel)
                        .collect(Collectors.toList());
        return CollectionModel.of(comments,
                linkTo(methodOn(CommentController.class).all()).withSelfRel());
    }

    @PostMapping("/adverts/{advertId}/comments")
    Comment newComment(@RequestBody Comment newComment) {
        return commentRepository.save(newComment);
    }

    @GetMapping("/adverts/{advertId}/comments/{id}")
    EntityModel<Comment> one(@PathVariable Long id) {
        Comment comment = commentRepository.findById(id)
                .orElseThrow(() -> new CommentNotFoundException(id));
        return assembler.toModel(comment);
    }

    @PutMapping("/adverts/{advertId}//comments/{id}")
    Comment replaceComment(@RequestBody Comment newComment,
                          @PathVariable Long id) {
        return commentRepository.findById(id)
                .map(comment -> {
                    comment.setAdvertId(newComment.getAdvertId());
                    comment.setComment(newComment.getComment());
                    return commentRepository.save(comment);
                })
                .orElseGet(() -> {
                    newComment.setId(id);
                    return commentRepository.save(newComment);
                });
    }

    @DeleteMapping("/adverts/{advertId}/comments/{id}")
    void deleteComment(@PathVariable Long id) {
        commentRepository.deleteById(id);
    }
}
@Component
public class CommentModelAssembler implements RepresentationModelAssembler<Comment, EntityModel<Comment>> {

    @Override
    public EntityModel<Comment> toModel(Comment comment) {
        return EntityModel.of(comment,
                linkTo(methodOn(CommentController.class).one(comment.getId())).withSelfRel(),
                linkTo(methodOn(CommentController.class).all()).withRel("comments"));
    }
}
@RestController
class UserController {

    private final UserRepository repository;
    private final UserModelAssembler assembler;

    UserController(UserRepository repository, UserModelAssembler assembler) {
        this.repository = repository;
        this.assembler = assembler;
    }

    @GetMapping("/users")
    CollectionModel<EntityModel<User>> all() {
        List<EntityModel<User>> users =
                repository.findAll().stream()
                        .map(assembler::toModel)
                        .collect(Collectors.toList());
        return CollectionModel.of(users,
                linkTo(methodOn(UserController.class).all()).withSelfRel());
    }

    @PostMapping("/users")
    User newUser(@RequestBody User newUser) {
        return repository.save(newUser);
    }

    @GetMapping("/users/{id}")
    EntityModel<User> one(@PathVariable Long id) {
        User user = repository.findById(id)
                .orElseThrow(() -> new UserNotFoundException(id));
        return assembler.toModel(user);
    }

    @PutMapping("/users/{id}")
    User replaceUser(@RequestBody User newUser,
                     @PathVariable Long id) {
        return repository.findById(id)
                .map(user -> {
                    user.setName(newUser.getName());
                    user.setRole(newUser.getRole());
                    user.setBoughtVehicles(newUser.getBoughtVehicles());
                    user.setSoldVehicles(newUser.getSoldVehicles());
                    return repository.save(user);
                })
                .orElseGet(() -> {
                    newUser.setId(id);
                    return repository.save(newUser);
                });
    }

    @DeleteMapping("/users/{id}")
    void deleteUser(@PathVariable Long id) {
        repository.deleteById(id);
    }
}
@RestController
class AdvertController {

    private final AdvertRepository repository;
    private final AdvertsModelAssembler assembler;

    AdvertController(AdvertRepository repository, AdvertsModelAssembler assembler) {
        this.repository = repository;
        this.assembler = assembler;
    }

    @GetMapping("/adverts")
    CollectionModel<EntityModel<Advert>> all() {
        List<EntityModel<Advert>> adverts =
                repository.findAll().stream()
                .map(assembler::toModel)
                .collect(Collectors.toList());
        return CollectionModel.of(adverts,
                linkTo(methodOn(AdvertController.class).all()).withSelfRel());
    }

    @PostMapping("/adverts")
    Advert newAdvert(@RequestBody Advert newAdvert) {
        return repository.save(newAdvert);
    }

    @GetMapping("/adverts/{id}")
    EntityModel<Advert> one(@PathVariable Long id) {
        Advert advert = repository.findById(id)
                .orElseThrow(() -> new AdvertNotFoundException(id));
        return assembler.toModel(advert);
    }

    @PutMapping("/adverts/{id}")
    Advert replaceAdvert(@RequestBody Advert newAdvert,
                         @PathVariable Long id) {
        return repository.findById(id)
                .map(advert -> {
                    advert.setAutoCategory(newAdvert.getAutoCategory());
                    advert.setAutoName(newAdvert.getAutoName());
                    advert.setAutoModel(newAdvert.getAutoModel());
                    advert.setComments(newAdvert.getComments());
                    return repository.save(advert);
                })
                .orElseGet(() -> {
                    newAdvert.setId(id);
                    return repository.save(newAdvert);
                });
    }

    @DeleteMapping("/adverts/{id}")
    void deleteAdvert(@PathVariable Long id) {
        repository.deleteById(id);
    }
}

localhost:8080/comments 结果:

{
  "_embedded" : {
    "comments" : [ {
      "advertId" : 1,
      "comment" : "That's a nice car!",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/comments/3"
        },
        "comment" : {
          "href" : "http://localhost:8080/comments/3"
        }
      }
    }, {
      "advertId" : 2,
      "comment" : "What a nice color of the car!",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/comments/4"
        },
        "comment" : {
          "href" : "http://localhost:8080/comments/4"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/comments"
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/comments"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 2,
    "totalPages" : 1,
    "number" : 0
  }
}

【问题讨论】:

  • 请添加完整的类,因为您的 RequestMapping 中没有汽车。
  • 请添加您当前的代码以及到目前为止您尝试过的代码。
  • 我添加了 CommentController
  • 你能解释一下reach这个词吗?因为,它们使用不同的 HTTP 方法进行了注释,所以这应该不是问题
  • 我想确保只能看到每个用户的 cmets,而不是所有可能的 cmets。所以使用 localhost:8080/cmets 没有意义。

标签: java spring-boot request-mapping


【解决方案1】:

您的localhost:8080/comments API 似乎来自不同的控制器,而不是您发布的这个。

更新: 如果您只想查看每个用户的评论,可以按照以下方式更改控制器定义,使其更通用和简单:

@RestController
@RequestMapping("/adverts")
class CommentController {

更新 2: 您需要更新您的控制器 URL 映射。通常,我们为特定的控制器/目的定义一个通用的 url-name。就像你的 CommonController 一样,你可以这样做:

@RestController
    @RequestMapping("/common")
    class CommentController {

查看名称/commom。然后,在此控制器下,添加其他 API,例如 /comments/all/comments/{id}/comments/others。要访问这些控制器方法,您必须遵循此层次结构,例如: /common/comments/all/common/comments/1 AdvertController 也是如此:

@RestController
@RequestMapping("/advert")
class AdvertController {

再次检查常见的 url-name /advert。此控制器下的 API 将具有如下命名: /all, '/{id}'。要访问此控制器方法,请以这种方式使用 URL: /advert/all, /advert/1 这应该清楚你的想法。 一件事,我已经从我展示的 url-example 中排除了 base-url localhost:8080 部分,请注意添加这个。 希望,这将达到您的目的。

【讨论】:

  • 感谢您的回复。但是通过删除 {id} 我不需要在我的类中的每个方法之后添加这个 {id} 来获取特定用户的 cmets,或者向用户添加评论吗?我的其他控制器都没有请求也没有获得与 cmets 关联的任何映射。其他控制器如何打开/cmets?谢谢。
  • 您必须为每个具有 pathVariable 的 API 传递 {id},如下所示:/adverts/comments/1 --for specific user-to add or delete or get, adverts/comments --for all users等等。这是标准方式
  • 我添加了所有控制器。但是我不能做/adverts/cmets/1,因为我没有指定具体的广告,可以吗?
  • 再次感谢您的回复。实际上,我非常了解层次结构原则,这就是我想通过在我的 CommentController 上方添加 /adverts/{id} 来实现的。我想实现这个层次结构:/adverts/1/cmets 或 /adverts/1/cmets/2 以显示特定广告的所有 cmets 或特定评论。问题是一样的:我可以通过 /cmets 访问所有 cmets,但我几乎声明了 RequestMapping("/adverts/{id}") 以访问所有 cmets。如果我不能清楚地解释我的问题,我很抱歉。
  • 首先,我认为没有任何理由使用/comments 将您重定向到所有 cmets API,因为这甚至没有定义。其次,在类的顶部使用路径变量不是一个好的设计。您能否通过使用调试器或打印日志来确认您的localhost:8080/comments 请求重定向到哪里?如果你从类的顶部删除路径变量更好,而不是在方法级别使用
猜你喜欢
  • 1970-01-01
  • 2020-01-08
  • 2018-05-09
  • 1970-01-01
  • 2017-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多