Handle org.thymeleaf.exceptions.TemplateInputException - spring-mvc

I have the following controller logic. However, if I navigate to a non-existing page (e.g. /random-page), I end up with a TemplateInputException. How can I catch this and go to the 404 page?
#RequestMapping(value = { "{path:(?!resources|error).*$}", "{path:(?!resources|error).*$}/**" }, headers = "Accept=text/html")
public String index(final HttpServletRequest request) {
try {
String path = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
return path.split("/")[1];
} catch (Exception e) {
log.error("Failed to render the page. {}",e);
return "error/general";
}
}
Thymeleaf seems to be ignoring the ExceptionHandler:
#ExceptionHandler(Exception.class)
public ModelAndView handleAllException(Exception ex) {
ModelAndView model = new ModelAndView("error/generic_error");
model.addObject("errMsg", "this is Exception.class");
return model;
}

My workaround this problem for spring-boot (exception is view with message param):
#Controller
public class ErrorController implements org.springframework.boot.autoconfigure.web.ErrorController {
private static final String ERROR_PATH = "/error";
#Autowired
private ErrorAttributes errorAttributes;
#Override
public String getErrorPath() {
return ERROR_PATH;
}
#RequestMapping(ERROR_PATH)
public String error(HttpServletRequest request, Model model) {
Map<String, Object> errorMap = errorAttributes.getErrorAttributes(new ServletRequestAttributes(request), false);
String exception = (String) errorMap.get("exception");
if (exception != null && exception.contains("TemplateInputException")) {
errorMap.put("message", "Неверный запрос");
}
model.addAllAttributes(errorMap);
return "exception";
}
}

Related

How to return HTTP response from HandlerMethodArgumentResolver

I have some controller's method:
#RequestMapping("/")
#AuthorizedRNUser
public Object index(UserStateVO userStateVO) {
return userStateVO;
}
Also I have HandlerMethodArgumentResolver for UserStateVO parameter
public class UserStateArgumentHandlerResovler implements HandlerMethodArgumentResolver{
#Autowired
RNService service;
#Override
public boolean supportsParameter(MethodParameter methodParameter) {
return methodParameter.getMethod().isAnnotationPresent(AuthorizedRNUser.class) && methodParameter.getParameterType() == UserStateVO.class;
}
#Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
UserStateVO userState = service.getUserState();
if (isNull(userState))
// here i need to return 403 HTTP response
throw new RuntimeException("User is not allowed");
return userState;
}
}
And if the UserStateVO is null I need to return 403 HTTP response, but I do not know is it possible? How best to check UserStateVO and pass it into a controller or return HTTP response?
Use the same method as handling exceptions in MVC exception-handling-in-spring-mvc
Add your custom exception, e.g
public class BadRequestException extends RuntimeException {
private static final long serialVersionUID = 1L;
public BadRequestException(String message) {
super(message);
}
}
And either annotate it with #ResponseStatus(value = HttpStatus.FORBIDDEN, reason = "User is not allowed") or add #ControllerAdvice class with method like
#ExceptionHandler(value = { BadRequestException.class })
#ResponseStatus(value = HttpStatus.FORBIDDEN)
#ResponseBody
public Map<String, String> handleBadRequestException(BadRequestException e) {
Map<String, String> retMessages = new HashMap<>();
retMessages.put("message", e.getMessage());
return retMessages;
}
what remains is just to throw it
if (isNull(userState))
// here i need to return 403 HTTP response
throw new BadRequestException("User is not allowed");

Spring Boot + Shiro + Thymleaf

I have some problems with my webapp. Here is my code:
Config:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"app.controllers", "app.service"})
public class MainStConfig extends WebMvcConfigurerAdapter {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/",
"classpath:/webjars/",
"classpath:/tempplates/"
};
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
}
#Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter() {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setLoginUrl("/login.html");
shiroFilter.setSuccessUrl("/index.html");
shiroFilter.setUnauthorizedUrl("/index.html?error");
Map<String, String> filterChain = new HashMap<>();
filterChain.put("/", "anon");
filterChain.put("/login", "authcBasic");
filterChain.put("/logout", "logout");
filterChain.put("/admin/**", "authc,roles[ADMIN]");
filterChain.put("/student/**", "authc,roles[STUDENT]");
filterChain.put("/teacher/**", "authc,roles[TEACHER]");
//filterChain.put("/student/**", "authc,roles[STUDENT]");
//filterChain.put("/teacher/**", "roles,roles[TEACHER]");
shiroFilter.setFilterChainDefinitionMap(filterChain);
shiroFilter.setSecurityManager(securityManager());
Map<String, Filter> filters = new HashMap<>();
filters.put("anon", new AnonymousFilter());
filters.put("authc", new FormAuthenticationFilter());
filters.put("logout", new LogoutFilter());
filters.put("roles", new RolesAuthorizationFilter());
filters.put("user", new UserFilter());
shiroFilter.setFilters(filters);
return shiroFilter;
}
#Bean
public org.apache.shiro.mgt.SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm());
return securityManager;
}
#Bean(name = "userRealm")
#DependsOn("lifecycleBeanPostProcessor")
public UserRealm userRealm() {
return new UserRealm();
}
#Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
}
IndexController:
#Controller
#RequestMapping("/")
public class IndexController {
#RequestMapping(value = "/", method = RequestMethod.GET)
String start() {
return "index";
}
#RequestMapping(value = "/index", method = RequestMethod.GET)
String index() {
return "index";
}
#RequestMapping("/login")
String login() {
return "login";
}
}
LoginController
#Controller
public class LoginController {
private Session session;
#ModelAttribute("userR")
public User getUser() {
return new User();
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
return "login";
}
#RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logoutt() {
return "redirect:/index";
}
#RequestMapping(value = "/admin/index", method = RequestMethod.GET)
public String admin() {
return "admin/index";
}
#RequestMapping(value = "/student/index", method = RequestMethod.GET)
public String student() {
return "student/index";
}
#RequestMapping(value = "/teacher/index", method = RequestMethod.GET)
public String teacher() {
return "teacher/index";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(Model model, #ModelAttribute("userR") User user, RedirectAttributes redirectAttrs, SessionStatus status) {
Subject currentUser = SecurityUtils.getSubject();
model.addAttribute("login", user.getLogin());
if (StringUtils.hasText(user.getLogin()) && StringUtils.hasText(user.getPassword())) {
try {
UsernamePasswordToken token = new UsernamePasswordToken(user.getLogin(), user.getPassword());
token.setRememberMe(true);
currentUser.login(token);
session = currentUser.getSession(false);
if(currentUser.hasRole("ADMIN")) {
status.setComplete();
return "redirect:/admin/index";
}
if(currentUser.hasRole("STUDENT")) {
status.setComplete();
return "redirect:/student/index";
}
if(currentUser.hasRole("TEACHER")) {
status.setComplete();
return "redirect:/teacher/index";
}
} catch (Exception e) {
return "login";
}
return "redirect:index";
} else {
return "login";
}
}
#RequestMapping(value = "/logout", method = RequestMethod.POST)/*#RequestMapping(value = "/logout", method = RequestMethod.POST)*/
public String logout() {
Subject currentUser = SecurityUtils.getSubject();
try {
session.stop();
currentUser.logout();
return "redirect:/index";
} catch (Exception e) {
return "redirect:/index";
}
}
}
So, with this code always when I'm starting index page in my console I can see pages without layout with css - white pages without bootstrap but when i change this method i LoginController:
#RequestMapping(method = RequestMethod.POST)
public String logout() {
Subject currentUser = SecurityUtils.getSubject();
try {
session.stop();
currentUser.logout();
return "redirect:/index";
} catch (Exception e) {
return "redirect:/index";
}
}
to:
#RequestMapping(value = "/logout", method = RequestMethod.POST)
then everything works, I can see all colors etc but here is problem now, When I try to log out, for example from /admin/index then I'm redirecting to /admin/logout with Whitable error. Should be redirecting to index page like without "value = "/logout"" because then it works.
I use fot log out button:
<form th:action="#{logout}" method="POST">
<input type="submit" class="btn btn-info text-center center-block"
value="Wyloguj" />
</form>
And when I'm not using this "value = "logout"" then after log out in console I can see this warning:
2017-01-06 19:40:56.135 WARN 3400 --- [nio-8080-exec-6] o.s.web.servlet.PageNotFound : Request method 'GET' not supported
What am I doing wrong?

Call EJB method by reflection have any Issues when code deploy on server?

I want to call an ejb method by reflection when i deploy my code to local glass-fish server it's work correctly. I want to know when load code main on server and have many call on that method, ejb architecture make some error?
#Stateless
public class AccessManager implements AccessManagerInt {
#EJB
public UserJpaControllerInt uj;
#EJB
public RoleJpaControllerInt rj;
#EJB
public ProductJpaControllerInt prj;
#EJB
public AppJpaControllerInt aj;
HashMap<String, Object> JPA_Mapper;
public Object doCreate(String JPA_Name, String methodName, String appCode, Integer userId, Class[] paramsType, Object[] params) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, AccassDeniedException {
User u = uj.findUser(userId);
Role r = rj.findRole(u.getId());
String tableName = JPA_Name.split("JpaControllerInt")[0];
if (haveAccess((String) TableTag.getInstance().get(tableName), (String) CRUD_Tag.getInstance().get("Create"), r) != -1) {
try {
Object obj = getJPA(JPA_Name);
Method method = obj.getClass().getDeclaredMethod(methodName, paramsType);
Product p = (Product) method.invoke(obj, params);
return p;
} catch (Exception ex) {
Logger.getLogger(AccessManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
throw new AccassDeniedException("YouHaveNoAccessToThisTable");
}
public Object doRead(String JPA_Name, String methodName, String appCode, String userId, Class[] paramsType, Object[] params) {
return null;
}
public Integer haveAccess(String tableTag, String CRUD_Tag, Role role) {
try {
JSONObject access = new JSONObject(role.getAccess());
JSONObject CRUD_Function = access.getJSONObject(CRUD_Tag);
return CRUD_Function.getInt(tableTag);
} catch (JSONException ex) {
Logger.getLogger(AccessManager.class.getName()).log(Level.SEVERE, null, ex);
}
return -1;
}
public Object getJPA(String JPA_Name) {
if (JPA_Mapper == null) {
JPA_Mapper = new HashMap<>();
for (Field field : this.getClass().getFields()) {
boolean flag = false;
for (Annotation annotation : field.getDeclaredAnnotations()) {
if (annotation.toString().contains("javax.ejb.EJB")) {
flag = true;
}
}
if (flag) {
try {
System.out.println("Add JPA-> "+field.getType().getSimpleName());
JPA_Mapper.put(field.getType().getSimpleName(), field.get(this));
} catch (IllegalArgumentException ex) {
Logger.getLogger(AccessManager.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(AccessManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
return JPA_Mapper.get(JPA_Name);
}
}

Spring MVC ExceptionHandler for restful and normal

I want to handle exception for both normal and rest/ajax requests. Here is my code,
#ControllerAdvice
public class MyExceptionHandler {
#ExceptionHandler(Exception.class)
public ModelAndView handleCustomException(Exception ex) {
ModelAndView model = new ModelAndView("error");
model.addObject("errMsg", ex.getMessage());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
sw.toString();
model.addObject("errTrace", sw);
return model;
}
#ExceptionHandler(Exception.class)
#ResponseBody
public String handleAjaxException(Exception ex) {
JSONObject model = new JSONObject();
model.put("status", "error");
model.put("errMsg", ex.getMessage());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
sw.toString();
model.put("errTrace", sw);
return model.toString();
}
}
This will give me an error as I cant have #ExceptionHandler(Exception.class) twice. So what could be the solution?
see the configuration of #ControllerAdvice:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
So you can create two classes(error handlers) and specify annotations/basePackages/assignibaleTypes
For example for REST(ajax) use #RestController annotation for your controllers and you can handle errors like this:
#ControllerAdvice(annotations = RestController.class)
public class MyExceptionHandler {
#ExceptionHandler(Exception.class)
#ResponseBody
public String handleAjaxException(Exception ex) {
...
}
}
for other cases it can be error handler with annotation
#ControllerAdvice(annotations = Controller.class)
This is global exception handler in spring mvc.this is called every time when exception found in your application.I think you to control only 404 exception with the help of web.xml.
#ControllerAdvice
public class GlobalExceptionController {
#ExceptionHandler(Throwable.class)
#ResponseBody
public ModelAndView handleAllException(Throwable ex,
HttpServletResponse response) {
ex.printStackTrace();
// Set Status
response.setStatus(500);
// Set View
ModelAndView model = new ModelAndView("500");
model.addObject("navlabel", "");
model.addObject("userActivity", new ArrayList<String>());
// Set exception Message
model.addObject("errMsg", ex.getMessage());
return model;
}
}
You can create inner static class #RestControllerAdvice. Noot needed to create separated #RestController for this.
#ControllerAdvice
public class BaseController {
private static final Logger logger =
LoggerFactory.getLogger(BaseController.class);
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleException(Exception error, Model model) {
logger.error("Error was: " + error.getMessage(), error);
model.addAttribute("message", error.getMessage());
model.addAttribute("stackTrace", error.getStackTrace());
model.addAttribute("exception", error);
return "error"; //return view
}
#RestControllerAdvice
public static class RestBaseController {
private static final Logger logger = LoggerFactory.getLogger(RestBaseController.class);
#ExceptionHandler(Exception.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleException(Exception error) {
logger.error("Error was: " + error.getMessage(), error);
return "error"; //return "error"
}
}
}
You can write two exception handler to handle both normal and rest/ajax requests exception. Here is sample code to illustrate the solution.
#ControllerAdvice(annotations = RestController.class)
#Order(1)
class RestExceptionHandler {
#ExceptionHandler(MyException.class)
#ResponseBody
ResponseEntity<ErrorResponse> exceptionHandler() {
....
}
}
#ControllerAdvice(annotations = Controller.class)
#Order(2)
class ExceptionHandler {
#ExceptionHandler(Exception.class)
public ModelAndView handleError500(HttpServletRequest request, HttpServletResponse response, Exception ex) {
ModelAndView mav = new ModelAndView("error");
mav.addObject("error", "500");
return mav;
}
}

PropertyEditorSupport method not executed

i want use spring mvc convert json to one object like
#RequestMapping(value = "searchPolygonArea/", method = RequestMethod.GET,params = {"region != null"})
public #ResponseBody ResultBean <List <Spot>> searchPolygonArea(#ModelAttribute (value="regionModel") Region regions,#RequestParam(value="region") Region region){
return new ResultBean <List<Spot>> ();
}
#InitBinder(value="regionModel")
public void initBinder(WebDataBinder dataBinder,#RequestParam(value="region") final String regionParams){//,
dataBinder.registerCustomEditor (Region.class, new PropertyEditorSupport (){
Region value ;
#Override
public Object getValue () {
return new Region ();
}
#Override
public void setAsText (String text) throws IllegalArgumentException {
System.out.println (text);
try {
value = JSONUtils.json2Obj (text, Region.class);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
but setAsText and getValue not executed , i don't know why.

Resources