英文:
How to pass model attributes globally to avoid repeatable code in Spring controller?
问题
以下是代码中需要翻译的部分:
Repeatable piece of code
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
Full method with that piece of code appearing twice
@PostMapping("/hotels/{hotelId}/rooms")
public String createRoomForHotelById(@ModelAttribute("room") @Valid NewRoomDto roomDto,
BindingResult result,
@PathVariable("hotelId") Long hotelId,
Model model) {
if(result.hasErrors()) {
// SAME CODE
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
//
model.addAttribute("hotel", new NewHotelDto());
LOG.info("Binding error: {}", result.toString());
return "admin/dashboard";
}
// SAME CODE
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
//
LOG.info("AdminController: CreateRoomForHotelById: Created room: {}", roomDto.toString());
roomDto.setHotelId(hotelId);
roomService.createNewRoom(roomDto);
return "redirect:/auth/admin/hotels/{hotelId}/rooms";
}
英文:
I would like to ask you for some best practice to reduce the amount of repeatable code in my controller's methods - one of them is presented below.
I have quite a big and complex view with a lot of information and two forms. In every method of my controller (and there are quite a few) I have to pass the same attributes to my view (in post controllers even twice). I added a note SAME CODE in the code snippet below indicating identical pieces of code.
I wonder if there is any possibility to make a one global method in the controller gathering all attributes to be passed to the model and just reference it in any of particular methods?
I looked into ModelAndView or ModelMap, but cannot see those being suitable here.
Just want to avoid repeating this part:
Repeatable piece of code
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
Full method with that piece of code appearing twice
@PostMapping("/hotels/{hotelId}/rooms")
public String createRoomForHotelById(@ModelAttribute("room") @Valid NewRoomDto roomDto,
BindingResult result,
@PathVariable("hotelId") Long hotelId,
Model model) {
if(result.hasErrors()) {
// SAME CODE
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
//
model.addAttribute("hotel", new NewHotelDto());
LOG.info("Binding error: {}", result.toString());
return "admin/dashboard";
}
// SAME CODE
model.addAttribute("hotels", hotelService.getAllHotels());
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
//
LOG.info("AdminController: CreateRoomForHotelById: Created room: {}", roomDto.toString());
roomDto.setHotelId(hotelId);
roomService.createNewRoom(roomDto);
return "redirect:/auth/admin/hotels/{hotelId}/rooms";
}
答案1
得分: 1
对于全局模型属性,您可以使用 @ControllerAdvice:
创建一个类,并用 @ControllerAdvice
进行注解。
在该类中,像这样传递模型属性(现在将全局可用):
@ModelAttribute("foo")
public Foo foo() {
return new Foo();
}
英文:
For global model attributes you can use @ControllerAdvice:
Create a class and annotate it with @ControllerAdvice
.
Inside of that class pass the model attribute (which will now be available globally) like so:
@ModelAttribute("foo")
public Foo foo() {
return new Foo();
}
答案2
得分: 1
你也可以将代码从J Asgarov的回答移到同一个控制器中,而不是放在另一个使用@ControllerAdvice
注解的类中。这样,该代码只会在该控制器内的@RequestMapping
方法中执行。
对于多个值,你也可以像这样做:
@ModelAttribute
public void foo(Model model, @PathVariable(required = false) Long hotelId) {
model.addAttribute("hotels", hotelService.getAllHotels());
if (hotelId != null) {
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
}
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
}
但根据你的代码,我更建议将重复的代码移到一个私有方法中,每当需要时调用它,比如你的createRoomForHotelById
方法会导致重定向,基本上会丢弃你放在模型中的所有内容。
英文:
You can also move the code from J Asgarov's answer into the same controller instead of another class annotated with @ControllerAdvice
. That way that code will only be executed for @RequestMapping
methods within that controller.
For multiple values you could also do something like this:
@ModelAttribute
public void foo(Model model, @PathVariable(required = false) Long hotelId) {
model.addAttribute("hotels", hotelService.getAllHotels());
if (hotelId != null) {
List<GetRoomDto> roomsDto = roomService.getAllRoomsByHotelId(hotelId);
model.addAttribute("rooms", roomsDto);
}
model.addAttribute("roomTypes", roomTypeService.findAllRoomTypeNames());
}
But seeing your code I would rather suggest you move the repeated code into a private method and call it whenever you need those inside your model.
Your method createRoomForHotelById
for example causes a redirect, which basically discards everything you put in your model.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论