Spring MVC - Redirect inside the Constructor - java

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>

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

Why can't my interceptor block certain URLs?

/** WebMvcConfig.class */
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new WebSecurityConfig())
.addPathPatterns("/**")
.excludePathPatterns("/login","/loginPost");
super.addInterceptors(registry);
}
/** WebSecurityConfig.class */
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean flag =true;
User user=(User)request.getSession().getAttribute("user");
if(null==user){
response.sendRedirect("/login");
flag = false;
}
return flag;
}
I added an interceptor that jumps to the login page when the user is not logged in. The interceptor works when I enter 'http://localhost:8011/git/vision'. But when I type this URL, 'http://localhost:8011/git/vision/index.html', the interceptor doesn't work. It means that I can access this resource without logging in. Can you help me solve this problem?

Issue with intercepting requests to controller

I want to create an abstract controller that will add the additional request mapping basen on actual mappings for the extending controller.
As an example, for the following controller
#Controller
public class MyController extends VariableResolvingController {
#RequestMapping("page.htm")
public void handlerMethod() {
}
}
I want it to extend VariableResolvingControllerthat will add a mapping to it's resolveContextVariable(...) method with the "page.htm.context" URI.
public abstract class VariableResolvingController {
public final #ResponseBody Object resolveContextVariable(String variableName) {
return "{}";
}
protected final void registerVariableResolver(String variableName, VariableResolver resolver) {
//...
}
}
This approach adds a possibility to resolve custom variables using eg. AJAX requests in a way almost transparent for a client code.
Do you know any existing solutions that would be appropriate in this case?
Solution: I achieved my goal by writing a custom HandlerMapping implementation (in essence a decorator for RequestMappingHandlerMapping).
One way of doing is add simple Servlet filter to your spring mvc
public class RequestCheckFilter implements Filter {
#Override
public void destroy() {
// ...
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
//
}
#Override
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
HttpServletRequest httpServletRequest = ((HttpServletRequest) request);
String requestURI = httpServletRequest.getRequestURI();
if (requestURI.endsWith(".context")) {
request.getRequestDispatcher(requestURI.concat(".htm"))
.forward(request,response);
} else {
chain.doFilter(httpServletRequest, response);
}
} catch (Exception ex) {
request.setAttribute("errorMessage", ex);
request.getRequestDispatcher("/WEB-INF/views/jsp/error.jsp")
.forward(request, response);
}
}
add it
public class MyWebInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
//...
#Override
protected Filter[] getServletFilters() {
return new Filter[]{new RequestCheckFilter()};
}
}
or in web.xml
<filter>
<filter-name>reqHandlerFilter</filter-name>
<filter-class>RequestCheckFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>reqHandlerFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

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

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

How to pass Attribute to View without having Model as parameter?

I'm overriding a method that belongs to super class. Method takes no parameter. Therefore, I'm unable to pass Objects to the View using Model. Anyone has any suggestion?
#Override
protected String connectView(){
// I'd like to include an object in Model here
// e.g. model.addAttribute(....)
// but unpossible because super does not take a Model as param
return "connect/status";
}
Without having at least the request object, I do not believe you can simply do what you are asking. However, there are a few options:
Use a servlet filter...add the required values to the session there
Use the Decorator Pattern, in which you would create a instance of your class (controller in this case) within another wrapper class. In your wrapper you would do the additional processing, then call the wrapped inner object (your wrapped controller), then do any final processing.
HandlerInterceptor like #sp00m suggests (although I have never used it, so I have no input there)
I am sure there are probably some other options out there, but I can't think of any others.
This should suit your needs, using a HandlerInterceptor, a custom annotation #Model and reflection.
Model.java
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Model {
}
RequestInterceptor.java
#Service
public class RequestInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException {
try {
Class<?> clazz = request.getClass();
if (clazz.isAnnotationPresent(Controller.class)) {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Model.class)) {
field.set(request, new ModelMap());
break;
}
}
}
} catch (IllegalAccessException e) {
// log("Cannot access model field of controller " + clazz.getSimpleName());
}
return true;
}
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
try {
Class<?> clazz = request.getClass();
if (clazz.isAnnotationPresent(Controller.class)) {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Model.class)) {
ModelMap model = (ModelMap) field.get(request);
if (model != null) {
modelAndView.addAllObjects(model);
}
break;
}
}
}
} catch (IllegalAccessException e) {
// log("Cannot access model field of controller " + clazz.getSimpleName());
}
}
#Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
applicationContext.xml
<!-- register the interceptor -->
<mvc:interceptors>
<bean class="your.package.to.the.RequestInterceptor" />
</mvc:interceptors>
YourController.java
#Controller
public class YourController extends ConnectController {
#Model
private ModelMap model;
#Override
protected String connectView(){
// model is here available
model.addAttribute("attrName", "attrValue");
return "connect/status";
}
}

Categories