Why is a GET request mapped to "/error" in Spring-Boot? - spring-boot

When I send a GET request to /todo-list/user/list
it was mapped to /error.
Code
Interceptor:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
RequestMapping classMapping = handlerMethod.getMethod().getDeclaringClass().getAnnotation(RequestMapping.class);
// when debugging: classMapping.value() was "${server.error.path:${error.path:/error}}"
RequestMapping methodMapping = handlerMethod.getMethodAnnotation(RequestMapping.class);
//some other codes
Controller:
//the contexPath is "/todo-list"
#RestController
#RequestMapping("/user")
#RequiredArgsConstructor
public class UserController
Method
#GetMapping(value = "/list")
public #ResponseBody Page<UserProjection> listGrid() {
return userService.listGrid();
}
I checked the address and method and whatever I think is the reason.
When debugging my code, classMapping.value() was equal to "${server.error.path:${error.path:/error}}".
What is the problem?

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());
}
...
}

Converting a responseEntity to httpServletResponse with spring

My controller method looks like this :
public void doLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
and I want to do this
ResponseEntity<String> responseEntity = restTemplate.postForEntity(testPrefix + "/login", map, String.class);
response = responseEntity;
or similar, basically make a restcall and return the HttpReponseEntity as the response n its enitirety
From updated comments I assume that you are wanting to return the result of the restTemplate.postForEntity() call from your Controller.
As shown by the Spring MVC documentation, ResponseEntity is a valid return type from a Controller method. So you can simply return the result of your restTemplate.postForEntity() call from the doLogin() method. As an example:
#Controller
public class MyController
{
#AutoWired
private RestTemplate restTemplate;
#RequestMapping("/yourPath")
public ResponseEntity<String> doLogin(HttpServletRequest request) throws IOException
{
return restTemplate.postForEntity(testPrefix + "/login", map, String.class);
}
}
Spring MVC will take care of marshalling the ResponseEntity into the HTML response using a HTTPMessageConverter.

Spring-MVC Exception handler returns OK when writing into response

I'm using spring-webmvc : 3.2.3.RELEASE (and its related dependencies).
I have this controller:
#Controller
#RequestMapping("/home")
public class HomeController {
#Autowired
MappingJacksonHttpMessageConverter messageConverter;
#RequestMapping(method = RequestMethod.GET)
public String get() {
throw new RuntimeException("XXXXXX");
}
#ExceptionHandler(value = java.lang.RuntimeException.class)
#ResponseStatus(HttpStatus.CONFLICT)
public ModelAndView runtimeExceptionAndView(ServletWebRequest webRequest) throws Exception {
ModelAndView retVal = handleResponseBody("AASASAS", webRequest);
return retVal;
}
#SuppressWarnings({ "resource", "rawtypes", "unchecked" })
private ModelAndView handleResponseBody(Object body, ServletWebRequest webRequest) throws ServletException, IOException {
ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(webRequest.getResponse());
messageConverter.write(body, MediaType.APPLICATION_JSON, outputMessage);
return new ModelAndView();
}
}
since the "/home" method throws RuntimeException that is being handled with the #ExceptionHandler, when the get() method is invoked, I'm expectin to get HttpStatus.CONFLICT, but instead, I'm getting HttpStatus.OK.
Can someone please tell me what should I do in order to get the response status from
the annotated exception handler?
The reason is because you are explicitly writing to the output stream, instead of letting the framework handle it. The header has to go before the body content is written, if you are explicitly handling writing to the output stream, you will have to write the header also yourself.
To let the framework handle the entire flow, you can instead do this:
#ExceptionHandler(value = java.lang.RuntimeException.class)
#ResponseStatus(HttpStatus.CONFLICT)
#ResponseBody
public TypeToBeMarshalled runtimeExceptionAndView(ServletWebRequest webRequest) throws Exception {
return typeToBeMarshalled;
}
Modify ExceptionHandler method like this
#ExceptionHandler(value = java.lang.RuntimeException.class)
public ModelAndView runtimeExceptionAndView(ServletWebRequest webRequest, HttpServletResponse response) throws Exception {
response.setStatus(HttpStatus.CONFLICT.value());
ModelAndView retVal = handleResponseBody("AASASAS", webRequest);
return retVal;
}
If you want to handle exception by json result, I suggest to use #ResponseBody with Automatic Json return.
#ExceptionHandler(value = java.lang.RuntimeException.class)
#ResponseBody
public Object runtimeExceptionAndView(ServletWebRequest webRequest, HttpServletResponse response) throws Exception {
response.setStatus(HttpStatus.CONFLICT.value());
return new JsonResult();
}

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