Pre-conditions within #RequestMapping method? - spring

I don't know how to redirect user if they do not meet certain preconditions for a #RequestMapping.
I have a simple form that after completion sends the user to "/secondForm" which is unrelated to "/firstForm", how can I restrict access to "/secondForm", if first form has not been completed?
What makes this more difficult for me there is a controller in the middle.
firstForm --- (submit)---> emailController ----(redirect)----> secondForm

If you want to redirect a user to another page when certain conditions are met, you can use an interceptor. Example interceptor class:
#Component
public class RedirectInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) {
if (request.getRequestURI().contains("secondForm") && modelAndView.getModel().get("someBoolean") == false {
try {
response.sendRedirect("/firstForm");
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
}
}
And register it in configuration class:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Autowired
RedirectInterceptor redirectInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(redirectInterceptor);
}
}
If you prefer xml configuration over java then you can alternatively use this in your spring config xml:
<mvc:interceptors>
<bean id="redirectInterceptor" class="path.to.your.interceptor.RedirectInterceptor"/>
</mvc:interceptors>

Found an additional way:
Using FlashAttribute, by assigning before the redirect in emailController that sets a value.
In applicationController, by using an if statement if there isn't a FlashAttribute then redirect is called to the root of the application.

Related

Get Request/Response Body&Header in Spring AOP

I want to get request/response body and header within my aspect before and after if it's available or how to get those .
I mean i think with before annotation should be work for request,
with after annotation should be work for response. Can be ?
What I've tried so far :
I tried logbook library it's very complicated for me i could'nt figured it out how to work with that.So i gave up.
The actuator can do trick but I am doing extra work like how many times the endpoints called etc.So therefore i can't use actuator.
Also i tried to get request headers like below at least but i think this headers coming same all the time.I couldn't get httpservletresponse like how httpservetrequest does.
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
then
request.getHeader("date") but what about requestbody ?
how to get requestbody ? responsebody ? repsonseheader ?
My aspect file :
#Aspect
#Component
public class AppAspect implements ResponseInfo{
#Before("execution(#(#org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
public void loggingStartPointRequests(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
}
#After("execution(#(#org.springframework.web.bind.annotation.RequestMapping *) * *(..))")
public void loggingEndPointRequests(JoinPoint joinPoint) throws IOException {
}
}
My Controller Class:
#RestController
public class MainController {
#GetMapping("/people") //
public ResponseEntity<Poeple> getAllPeople(#RequestParam(name = "page", required = false) Integer page,
#RequestParam(name = "size", required = false) Integer size,
#RequestParam(name = "sortBy", required = false) Boolean sortByNameOrEpCount) {
doSomething();
}
}
I had the same problem and if you have your #Aspect annotated with #Component (or any #Autowired candidate) you can simply get the HttpServletRequest like this:
#Aspect
#Component
public class SomeAspect {
#Autowired
HttpServletRequest request;
#Before("...")
public void beforeAdvice(JoinPoint jp){
/* You will have the current request on the request property */
System.out.println(request.getRequestURL());
}
}
I know this is an old question but I hope it'll be helpful.
I think what you need is to implement the interface HandlerInterceptor, it would help you being able to inspect the request and the response. For example:
public class ApiMonitor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// when the client access to your endpoint
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
// when you finished your process
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// after you already returned an answer to the client
}
}
If you want to operate with the object that you're returning just before you send it to the client, then you need AOP, yes. That's an example of how I do it to modify an object on certain endpoints just before it's parsed to json.
#Component
#Aspect
public class MyCustomAOPInterceptor {
/**
* These poincuts check the execution of a method in any (*)
* class of my.package.controller and that start with
* get/list/find plus any other word (*) . For example
* my.package.controller.UserController.getUserById()
*/
#Pointcut("execution(* my.package.controller.*.get*(..))")
public void petitionsStartWithGet() { }
#Pointcut("execution(* my.package.controller.*.list*(..))")
public void petitionsStartWithList() { }
#Pointcut("execution(* my.package.controller.*.find*(..))")
public void petitionsStartWithFind() { }
#AfterReturning(pointcut = "petitionsStartWithGet() || petitionsStartWithList() || petitionsStartWithFind()", returning = "result")
public void translateEntities(JoinPoint joinPoint, Object result) {
// do your stuff; result is the object that you need
}
}

How to not use aspect in spring to write the request param and response param to the console

I found the class InvocableHandlerMethod.invokeForRequest will get the request param from request and invoke the controller class to get the return value.
What should I modify the method to write the params to the console?
I want to extends ServletInvocableHandlerMethod and override the method invokeForRequest but I can't call getMethodArgumentValues because it is private.should I copy the class of ServletInvocableHandlerMethod and InvocableHandlerMethod to modify the private method? Or is there have another way to log the request and response params without aspect?
Just create interceptor
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class LoggingInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// log here
return true; // let go further
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// log here
}
}
and register it
// example for Spring MVC annotation-based configuration
public class YourWebConfig extends WebMvcConfigurer {
...
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggingInterceptor());
}
...
}

Creating Custom AuthenticationSuccessHandler and calling default AuthenticationSuccessHandler when done

i want to create CustomAuthenticationSuccessHandler to add log to each user login:
class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
UserService getUserService() {
return ApplicationContextHolder.getBean('userService')
}
#Override
public void onAuthenticationSuccess(HttpServletRequest req,
HttpServletResponse res, Authentication auth) throws IOException,
ServletException {
userService.postLoginMessage(auth.principal.username, null)
}
}
it's simple enough code and works well, but now i have no return value. is there a way to call the default AuthenticationSuccessHandler after my custom code run or to return default value?
I mean to return the Authentication json.
You're doing it wrong essentially.
Instead of overriding the success handler, you should register an event listener.
Config:
grails.plugin.springsecurity.useSecurityEventListener = true
Register a class as a bean
class MySecurityEventListener
implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
#Autowired
UserService userService
void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
userService.postLoginMessage(event.authentication.principal.username, null)
}
}

SpringMVC Invoking a global method

I am a beginner in springMVC so take it easy on me guys...i am trying to invoke a method every time a user enters my web application regardless of the page/place.
I tried ContextRefreshedEvent but it only works when the application starts.
Is there any way to achieve this ?
Example would be
public class MyInterceptoor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
}
}
It is required to wire interceptor in your config.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/myproject/**"/>
<bean class="com.mvc.myproject.MyInterceptoor" />
</mvc:interceptor>
</mvc:interceptors>
Spring Documentation HandlerInterceptorAdapter
You can use Spring Interceptor – HandlerInterceptor.
http://www.journaldev.com/2676/spring-mvc-interceptor-example-handlerinterceptor-handlerinterceptoradapter
For SpringBoot you can do this. Make a HandlerInterceptorAdaptor
#Component
public class AccessInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("preHandled for controller = " + handler);
return true;
}
}
Add it to a Spring WebMvcConfiguration class:
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Autowired
AccessInterceptor accessInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(accessInterceptor).addPathPatterns("/**");
}
}
Enjoy ...

how to get returned value of my controllers from HandlerInterceptor

I'm creating a log manager for my controllers that logs every action in it and returned values
My controllers are defined in this way:
#Controller
#RequestMapping(value="/ajax/user")
public class UserController extends AbstractController{
#RequestMapping(value="/signup")
public #ResponseBody ActionResponse signup(#Valid SignupModel sign) {
ActionResponse response=new ActionRespone();
response.setMessage("This is a test message");
return response;
}
}
and I defined a HandlerInterceptor to log output of each handler:
#Component
public class ControllerInterceptor implements HandlerInterceptor {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return true;
}
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception {
LogManager log=new LogManager();
log.setMessage();//I need returned ActionResponse here
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
where I use log.setMessage(); I need my ActionResponse's message (This is a test message) which is returned from signup method
How can I do this?
An interceptor is not the right place to do what you want since it's not capable of getting the return value of the handler.
You can achieve what you wan't without changing any existing code using aspect oriented programming (AOP). For this to work in spring you'll need to include the jars for spring-aop and AspectJ.
Creating the aspect and advice
#Aspect
#Component
public class ActionResponseLoggerAspect {
private static final Logger logger = LoggerFactory.getLogger(ActionResponseLoggerAspect.class);
#AfterReturning(pointcut="execution(* your.package.UserController.*(..)))", returning="result")
public void afterReturning(JoinPoint joinPoint , Object result) {
if (result instanceof ActionResponse) {
ActionResponse m = (ActionResponse) result;
logger.info("ActionResponse returned with message [{}]", m.getMessage());
}
}
}
The afterReturning method will be executed every time a controller method returns.
Enabling #AspectJ Support
Enable AspectJ support by adding this to your XML configuration.
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
For more info see the spring docs.

Resources