I have written some RESTful webservices using Spring Framework (by reading posts online / video tutorials etc.) , however I still have some doubts.
When we write a web-application using Spring MVC module we use controller code, similar to below:
#Controller
public class SimpleController {
#RequestMapping("/welcome")
ModelAndView handleIncomingWelcomeReq() {
ModelAndView mw = new ModelAndView("WelcomePage","welcomeKey","WelcomeKey's value!");
return mw;
}
}
In the above code there is ModelAndView object which this controller returns, and this can be invoked like this URL:
http://localhost:8080/contextRoot/welcome
Now, if we exclude the "view" part and return just the model doesn't it act like a web service?
So my doubt is, in Spring do we used the same API/jar's to create web-application or RESTful web services?
The things which I read is that for Spring REST support, it has annotation #RestController annotation (which itself is like #Contoller + #ResponseBody annotations).
So what is the difference in which the implementation of REST WS and web-applications differs in Spring Framework?
Can anyone help me understand this?
Yes we can write RestService & web application using Spring. Use #RestController to expose a REST service and #Controller for web application.
#RestController is a meta-annotation with #Controller and #ResponseBody. #Controller will search through the registered ViewResolvers, whereas #RestController will not.
#Controller
public class SimpleController {
#RequestMapping("/welcome", method = RequestMethod.GET, produces="application/json")
public #ResponseBody JSONObject handleIncomingWelcomeReq() {
JSONObject j = new JSONObject();
j.put("welcomeKey", "WelcocmeKey's value!");
return j;
}
Here is the code which returns response in json mostly user id Rest Apis.
I would suggest to use #Controller instead of #RestController, as #RestController, won't scan your views. So, in case if your application has it's own views and also needs to expose it's services, you can use #Controller along with the #ResponseBody annotations, with output as JSON.
Another option is to have completely different URL for RESTful webservices, where a different controller will handle the request. These different controllers can be annotated with #RestController.
Related
I have several controller functions separated by role, and instead of doing role validation in each controller method, I found that it seems to be able to get done by using Aspect, however something isn't right in my implementation as the code in Aspect never runs
Annotation:
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface ForMerchantOnly {}
Aspect:
#Aspect
#Configuration
public class ForMerchantOnlyAspect {
private static final Logger logger = LogManager.getLogger(ForMerchantOnlyAspect.class);
#Before("#annotation(com.example.api.annotation.ForMerchantOnly) && args(request)")
public void before(HttpServletRequest request) throws ServiceException {
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("request should be HttpServletRequesttype");
}
String domain = request.getServerName();
System.out.println("Aspect showing domain " + domain);
// -- other code
}
}
Controller
#ForMerchantOnly
#GetMapping("/list")
public ResponseEntity<ApiResp> list() {
System.out.println("Show something");
return ResponseEntity.ok().body();
}
I'm assuming when i call controller /list method via chrome browser, it would hit the code in ForMerchantOnlyAspect but it just went into the controller method directly. Am I missing something?
The Aspect was not working as it could not find a matching joinpoint . There are no controller methods that has annotation #ForMerchantOnly and has an argument of type HttpServletRequest
From the documentation :
args: Limits matching to join points (the execution of methods when
using Spring AOP) where the arguments are instances of the given
types.
Following aspect may be used for the requirement . Scoping designator within will set the scope to advice.
#Before("#annotation(com.example.api.annotation.ForMerchantOnly) && within(com.example.api..*)")
public void before() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
System.out.println("Aspect showing domain " + request.getServerName());
}
Also note that an Aspect is better annotated with #Component and #Configuration be used for configurations.
You may also have a look at Method Security of Spring security framework , which lets to secure a method with annotations.
From the documentation
From version 2.0 onwards Spring Security has improved support
substantially for adding security to your service layer methods. It
provides support for JSR-250 annotation security as well as the
frameworkâs original #Secured annotation. From 3.0 you can also make
use of new expression-based annotations. You can apply security to a
single bean, using the intercept-methods element to decorate the bean
declaration, or you can secure multiple beans across the entire
service layer using the AspectJ style pointcuts.
Can we have multiple controllers in a Spring MVC application? If yes, can someone provide a working example to support this concept?
Of course you can. There's not much to provide:
#RestController
public class UserController {
#GetMapping("/users")
// method etc.
}
#RestController
public class AccountController{
#GetMapping("/accounts")
// method etc.
}
#PostMapping("/api/file/delete")
public String deleteMultipartFile(HttpServletRequest request) {
try {
String keyname=request.getParameter("keyname");
s3Services.deleteFile(keyname);
return "redirect:/welcome";
} catch(Exception e) {
return "redirect:/welcome";
}
}
Actual result :
printing "redirect:/welcome " in white page
Expected Result : it redirect to welcome modal.
Spring is a Java application framework and Spring boot is an evloution of Spring that helps create stand-alone, production-grade spring based application that you can "just run".
Spring boot supports #Controller and #RestController annotation, where
#Controller annotation indicates that the annotated class is a controller. It is a specialization of #Component and is autodetected through classpath scanning. It is typically used in combination with annotated handler methods based on the #RequestMapping annotation. #RestController is a sibling convenience annotation for creating Restful controllers.
If you created spring boot application having controller with annotation #Controller and you have #GetMapping method which return index.html(file location /src/main/resources/templates/index.html) view page. like code below :-
#Controller
public class MyController{
#GetMapping("/")
public String indexPage(){
return "index";
}
#GetMapping("/index")
public String routeWithIndex(){
return "redirect:/";
}
}
Both function returns index.html page. If you want more knowledge about spring annotation of #Controller and #RestController with examples visit baeldung site or official site about spring.
Return view page with #RestController in spring and use as rest service.
#RestController is a convenience annotation that combines #Controller and #ResponseBody. #ResponseBody on the other hand indicates that a method return value should be bound to the response body.
So either you have a #RestController and return objects or you could create #Controller and just have some of the methods annotated as #ResponseBody and some returning views.
Have a look at these resources:
Rest Controller Javadoc
Response body Javadoc
Article with deeper explanation
I was using spring annotations to map url to method, as shown in below code.
#Controller
public class HomeController {
#RequestMapping(value="/admin/dashboard.htm" ,method=RequestMethod.GET)
public String dashboard(HttpServletRequest request,HttpServletResponse response) {
.....
return "success";
}
}
I have removed spring annotations by spring xml.
Previously I was accessing method using
localhost:8888/admin/dashboard.htm url.
Now without annotations I need to use localhost:8888/home/dashboard.htm url to access method. I am using Controller Class Name HandlerMapping now.
What i need is, i want to access dashboard method using previous url localhost:8888/admin/dashboard.htm without annotations.
You should have a look at BeanNameUrlHandlerMapping (or take a lookControllerBeanNameHandlerMapping) described in Spring 2.5, which seems to do, what you want. But Why would anyone want that?