Is there a way, value defined in one main controller, can be accessed from all the other spring mvc controller? - spring

Something like this:
#Controller
public class HomeController {
public String getCurrentUserDetails() {
String username = "testuser";
return username;
}
}
#Controller
public class DashboardController {
#RequestMapping("/admin/dashboard")
public ModelAndView showDashbard() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username", GET username FROM HOME CONTROLLER [HomeController's getCurrentUserDetails]);
modelAndView.setViewName("/admin/dashboard");
return modelAndView;
}
}
#Controller
public class ProfileController {
#RequestMapping("/admin/profile")
public ModelAndView showProfile() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username", GET username FROM HOME CONTROLLER [HomeController's getCurrentUserDetails]);
modelAndView.setViewName("/profile/dashboard");
return modelAndView;
}
}
Yes I know I can instantiate the HomeController and get the object. But making object in every controller is hectic.
I just want the value of one controller available in all other controllers.

Related

How to implement REST API on a RestController using ModelAndView

Im struggling on how to implement a API when the methods in my controller are returning a ModelAndView. Most tutorials I can find are returning ResponseEntities. Should i be making seperate API controllers which strictly handle the API calls under a /api mapping? (which i believe isn't RESTFUL practice). Or is it possible to handle my API calls in the same controller, even when making use of ModelAndView?
My controller looks as following:
#RestController
#RequestMapping("/dish")
public class DishController {
private final DishRepository dishRepository;
public DishController(DishRepository dishRepository) {
this.dishRepository = dishRepository;
}
#GetMapping
public ModelAndView list() {
Iterable<Dish> dishes = this.dishRepository.findAll();
return new ModelAndView("dishes/list", "dishes", dishes);
}
#GetMapping("{id}")
public ModelAndView view(#PathVariable("id") Dish dish) {
return new ModelAndView("dishes/view", "dish", dish);
}
#GetMapping(params = "form")
#PreAuthorize("hasRole('ROLE_ADMIN')")
public String createForm(#ModelAttribute Dish dish) {
return "dishes/form";
}
#ResponseStatus(HttpStatus.CREATED)
#PostMapping
#PreAuthorize("hasRole('ROLE_ADMIN')")
public ModelAndView create(#Valid Dish dish, BindingResult result,
RedirectAttributes redirect) {
if (result.hasErrors()) {
return new ModelAndView("dishes/form", "formErrors", result.getAllErrors());
}
dish = this.dishRepository.save(dish);
redirect.addFlashAttribute("globalMessage", "view.success");
return new ModelAndView("redirect:/d/{dish.id}", "dish.id", dish.getId());
}
#RequestMapping("foo")
public String foo() {
throw new RuntimeException("Expected exception in controller");
}
#ResponseStatus(HttpStatus.OK)
#GetMapping("delete/{id}")
#PreAuthorize("hasRole('ROLE_ADMIN')")
public ModelAndView delete(#PathVariable("id") Long id) {
this.dishRepository.deleteById(id);
Iterable<Dish> dishes = this.dishRepository.findAll();
return new ModelAndView("dishes/list", "dishes", dishes);
}
#ResponseStatus(HttpStatus.OK)
#GetMapping("/modify/{id}")
#PreAuthorize("hasRole('ROLE_ADMIN')")
public ModelAndView modifyForm(#PathVariable("id") Dish dish) {
return new ModelAndView("dishes/form", "dish", dish);
}
You should not use Model and View in RestController. The main goal of RestController is to return data, not views. Take a look here for more details: Returning view from Spring MVC #RestController.
#RestController is a shorthand for writing #Controller and #ResponseBody, which you should only use if all methods are returning an object that should be treated as the response body (eg. JSON).
If you want to combine both REST endpoints and MVC endpoints within the same controller, you can annotate it with #Controller and individually annotate each method with #ResponseBody.
For example:
#Controller // Use #Controller in stead of #RestController
#RequestMapping("/dish")
public class DishController {
#GetMapping("/list")
public ModelAndView list() { /* ... */ }
#GetMapping
#ResponseBody // Use #ResponseBody for REST API methods
public List<Dish> findAll() { /* ... */ }
}
Alternatively, as you've mentioned, you can use multiple controllers:
#Controller
#RequestMapping("/dish")
public class DishViewController { /* ... */ }
#RestController
#RequestMapping("/api/dish")
public class DishAPIController { /* ... */ }

Spring MVC architecture

I have three .jsp pages on my app (index, user and admin). And I have three controllers for everything page but in my administration and user controllers use duplicate methods. For example, I have a method "getGenres" (For shows all genres from DB) in admin controller and user controller. How can I combine these methods if "#RequestMapping" is different in controllers?
#Controller
#EnableWebMvc
#RequestMapping("admin")
public class AdminController {
#Autowired
private GenreTableService genreService;
#RequestMapping(value = "genres")
public ResponseEntity<Map<String, List<Genre>>> getGenres() throws ServiceException {
Map<String, List<Genre>> genres = new HashMap<>(1);
genres.put("genres", genreService.getAll());
return new ResponseEntity<>(genres, HttpStatus.OK);
}
You want to combine methods. this is sample code.
enter link description here
enter link description here
like this :
#Controller
#RequestMapping("/common")
public class AdminController {
#Autowired
private GenreTableService genreService;
#RequestMapping(value = "/genres")
public ResponseEntity<Map<String, List<Genre>>> getGenres() throws ServiceException {
Map<String, List<Genre>> genres = new HashMap<>(1);
genres.put("genres", genreService.getAll());
return new ResponseEntity<>(genres, HttpStatus.OK);
}
}
or
#Controller
public class AdminController {
#Autowired
private GenreTableService genreService;
#RequestMapping(value = {"/admin/genres", "/user/genres"})
public ResponseEntity<Map<String, List<Genre>>> getGenres() throws ServiceException {
Map<String, List<Genre>> genres = new HashMap<>(1);
genres.put("genres", genreService.getAll());
return new ResponseEntity<>(genres, HttpStatus.OK);
}
}

Handle form submission in SpringBoot

Here is my controller:
#Controller
#RequestMapping("/accounts/*")
public class AccountController {
#Autowired
private AccountService accountService;
#GetMapping
public ModelAndView home() {
final ModelAndView modelAndView = new ModelAndView();
final List<Account> accountsForCurrentUser = this.accountService.getAccountsForCurrentUser();
modelAndView.addObject("accounts", accountsForCurrentUser);
modelAndView.setViewName("pages/accounts/index");
return modelAndView;
}
#GetMapping("create")
public ModelAndView create() {
final ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("account", new Account());
modelAndView.setViewName("pages/accounts/create");
return modelAndView;
}
#PostMapping("create")
public ModelAndView createSubmit(#Valid #ModelAttribute(name = "account") Account account, BindingResult bindingResult, ModelAndView modelAndView) {
if (bindingResult.hasErrors()) {
return modelAndView;
}
return new ModelAndView("redirect:/accounts");
}
}
What I'd like to do is redirecting user to /accounts/ when the form is validated but taking him back to /accounts/create/ with errors shown if errors has been reported.
But, on error, I have:
Error resolving template "accounts/create", template might not exist or might not be accessible by any of the configured Template Resolvers
You also need set model and view name in post/create method.
By the way, handling methods with ModelAndView is valid but I think it would be better to use the String approach. It's much better to read and a standart way. So your controller will look like:
#Controller
#RequestMapping("/accounts")
public class AccountController {
#Autowired
private AccountService accountService;
#GetMapping("")
public String home(Model Model) {
List<Account> accountsForCurrentUser = this.accountService.getAccountsForCurrentUser();
model.addAttribute("accounts", accountsForCurrentUser);
return "pages/accounts/index";
}
#GetMapping("/new")
public String newAccount(Model model) {
model.addAttribute("account", new Account());
return "pages/accounts/create";
}
#PostMapping("/new")
public String createAccount(#Valid #ModelAttribute Account account, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "pages/accounts/create";
}
"redirect:/accounts";
}
}

localhost:8080/ returns status 404 - Spring

This is my code:
#Controller
#RequestMapping("/")
public class MerchantsController {
#Autowired
MerchantsService merchantsService;
#Autowired
ProductsService productsService;
#Autowired
OrdersService ordersService;
#RequestMapping(value = "/merchants", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
As I understand when I send request to localhost:8080/ it should open localhost:8080/merchants, but it is not working. Anyone has any suggestions?
Your showMerchantsList method will be called when you send request to localhost:8080/merchants. And this method will you redirect again localhost:8080/merchants. But if you want send request as localhost:8080/ and direct you to localhost:8080/merchants, then you should create another method as this:
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showMerchantsListWithoutRequestMapping() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
This method will redirect you to localhost:8080/merchants, when you called localhost:8080/
Normal way you should use
#Controller
public class MerchantsController {
#Autowired
MerchantsService merchantsService;
#Autowired
ProductsService productsService;
#Autowired
OrdersService ordersService;
#RequestMapping(value = "/merchants", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
As i understand your requirement silly way:
#Controller
public class MerchantsController {
#Autowired
MerchantsService merchantsService;
#Autowired
ProductsService productsService;
#Autowired
OrdersService ordersService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView model=new ModelAndView("redirect:/merchants");
return model;
}
#RequestMapping(value = "/merchants", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
Note: Because / always denotes to root.

Spring MVC Index Controller Strict Request

Trying to map the index controller correctly.
#Controller
#RequestMapping("/")
public class ClientIndexController
{
#RequestMapping(method=RequestMethod.GET)
public ModelAndView index()
{
}
}
or
#Controller
public class ClientIndexController
{
#RequestMapping("/")
public ModelAndView index(HttpServletRequest request)
{
}
}
These both approaches could not distinguish two different requests.
http://domain.com/
http://domain.com/?test=1 - in this case 404 must be thrown.
How can I avoid such behavior?
You can have Map with all request parameters, and check if the map is empty. Then you can implement a lot of different ways in creating a 404 (the one in the example below in only one way (maybe not the best)).
#Controller
#RequestMapping("/")
public class ClientIndexController {
#RequestMapping(method=RequestMethod.GET)
public ModelAndView index(#RequestParam Map<String,String> allRequestParams) {
if(allRequestParams != null && !allRequestParams.isEmpty() {
throw new ResouceNotFoundException();
}
}
#ExceptionHandler(ResouceNotFoundException.class)
#ResponseStatus(404)
public void RprocessValidationError(ResouceNotFoundException ex) {
}
}
If you only want to check that a special parameter is not there then you could use
#RequestMapping(method = RequestMethod.GET, params="!test")
public ModelAndView index(){...}

Resources