spring mvc: how to add custom annotion on parameters to controllers - java

This is my controller class:
#Component
#RequestMapping("/test")
public class MyController
{
#RequestMapping(value = {"test"}, method = RequestMethod.GET)
#ResponseBody
public String test(#MyAnnotation String myValue)
{
return "myValue:"+myValue;
}
}
Moreover, below is my interceptor class:
public class MyInterceptor implements HandlerInterceptor
{
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
MyAnnotation annotation = ((HandlerMethod)handler).getMethod().getAnnotation(MyAnnotation.class);
// TODO
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
{
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) throws Exception
{
}
}
if I want myValue to be "test", then how to implement the custom annotation #MyAnnotation? what to do in class MyInterceptor

Related

Injecting Interceptor jar file to my spring boot projects

I am trying to create a jar file to inject into any of my spring boot project for logging the request details.
I am able to do this in one of my project. You can see the code below.
How to create the jar out of it and how to inject into other projects?
#Component
public class Interceptor extends HandlerInterceptorAdapter {
private static Logger log = LoggerFactory.getLogger(Interceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// log.info("Inside prehandle");
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// log.info("Inside postHandle");
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("Inside afterCompletion");
sendToLoggerApi(request, response);
}
}
#Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
#Autowired
Interceptor interceptor;
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(interceptor);
}
}

Spring Boot OncePerRequestFilter shouldNotFilter Junit

I am trying to add junit test case for my Spring Boot OncePerRequestFilter shouldNotFilter method logic. The logic works fine with real-time REST calls but junit case is failing. Any idea?.
Here is test code.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringFilterTest {
#Test
public void getHealthTest() throws Exception {
standaloneSetup(new PersonController()).addFilter(new SkipFilter()).build().perform(get("/health")).andExpect(status().isOk());
}
#Test
public void getPersonTest() throws Exception {
standaloneSetup(new PersonController()).addFilter(new SkipFilter()).build().perform(get("/person")).andExpect(status().isAccepted());
}
private class SkipFilter extends OncePerRequestFilter {
private Set<String> skipUrls = new HashSet<>(Arrays.asList("/health"));
private AntPathMatcher pathMatcher = new AntPathMatcher();
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
response.setStatus(HttpStatus.ACCEPTED.value());
}
#Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
}
}
#RestController
#RequestMapping(value = "/")
private static class PersonController {
#GetMapping("person")
public void getPerson() {
}
#GetMapping("health")
public void getHealth() {
}
}
}
I am expecting both of junit #Test cases to be successful but health one is always failing(its using Filter).
Incase, if you want to replicate below is complete repo code.
https://github.com/imran9m/spring-filter-test
Below Expression evaluates to false with request.getServletPath() when /health
skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
Change to request.getRequestURI() to get the uri and below condition matches the path
skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getRequestURI()));

How to get the value of parameter annotated with #RequestBody in a method interceptor?

I have a controller which has a #RequestBody annotation in one of its parameters. The parameter also has a custom annotation #JsonData.
public String updateUIMetadata(#PathVariable("caseId") final String caseId,
#RequestBody #JsonData(schemaLocation = "schema/metadata_schema.json") final String metadataJson) {
//...
}
I have a method interceptor which intercepts this method. I want to get hold of the value of metadataJson in my interceptor. I have tried using the handler object to get the method and the get theparameters but they do not seem to hold the value of the parameters. Is there anyway I can get the value with which metadataJson has been populated with in my interceptor class? Below is what I have tried.
public class ValidateJson implements HandlerInterceptor{
#Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception exception)
throws Exception {
// TODO Auto-generated method stub
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
MethodParameter[] mparams = handlerMethod.getMethodParameters();
Method method = handlerMethod.getMethod();
Object[] allArgs = method.getParameters();
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterAnnotations.length; i++) {
Annotation[] annotations = parameterAnnotations[i];
for(Annotation annotation: annotations) {
if (annotation instanceof com.fico.cardinal.cm.utils.JsonData) {
System.out.println(allArgs[i].toString());
}
}
}
return true;
}
return false;
}
}
This just prints java.lang.String arg1

Spring MVC - Redirect inside the Constructor

I would like to know how am I able to redirect the request inside the controller constructor if I need to do it?
For example: Inside the constructor I need to check some condition and if doesn't met I want to redirect to some other place. At the same way the rest of the constructor will not be executed neither the "original following action". I want the code like this.
#Controller
class SampleController{
public SampleController(){
if(![some condition]){
...redirecting code...
}
...rest code...
}
...rest code...
}
EDIT
If constructor is not a good option or approach then is there any option like before filter that will execute always before every action of a constructor and will redirect on the failure of some conditions?
You could use an interceptor:
public class CheckInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException {
if (handler instanceof TheController) {
// or for any controller: if (handler.getClass().isAnnotationPresent(Controller.class))
if (!check()) {
redirect("/check-failure.html");
return false;
}
}
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
private void redirect(HttpServletRequest request, HttpServletResponse response, String path) throws ServletException {
try {
response.sendRedirect(request.getContextPath() + path);
} catch (IOException e) {
throw new ServletException(e);
}
}
private boolean check() {
return ...
}
}
Then register it within the applicationContext.xml:
<mvc:interceptors>
<bean class="your.package.CheckInterceptor" />
</mvc:interceptors>

How to request complete query string in Spring MVC?

In Spring MVC, I can do this to get a value of items on the query string:
public void sendMessage(HttpServletResponse response,
#RequestParam("Session Id") String sessionId,
But how to I get the complete querystring as one long string? I.e. I don't want individual parameters from it, I want the whole thing?
Many thanks!
Add the HttpServletRequest as argument to the method, and get the query string from the request:
public void sendMessage(HttpServletRequest request,
HttpServletResponse response {
String queryString = request.getQueryString();
}
If you don't want to use HttpServletRequest in your controller, you can create HandlerMethodArgumentResolver that resolves query string.
Example:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
public #interface QueryString {
}
public class QueryStringResolver implements HandlerMethodArgumentResolver {
#Override
public boolean supportsParameter(MethodParameter parameter) {
Annotation[] parameterAnnotations = parameter.getParameterAnnotations();
for (Annotation parameterAnnotation : parameterAnnotations) {
if (QueryString.class.isInstance(parameterAnnotation)) {
return true;
}
}
return false;
}
#Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
return request.getQueryString();
}
}
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="mypackage.QueryStringResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
public class MyController {
#RequestMapping(...)
public String someMethod(#QueryString String queryString) {
...
}
}
Something like this you need to do:
public void sendMessage(HttpServletResponse response,
#RequestParam("Session Id") String sessionId, HttpServletRequest request,..
{
String qString= request.getQueryString();
The Controller itself knows the contents of the entire query string.
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception
You can then get the full query string from:
request.getQueryString();

Categories