Extending the JSTL View class - spring

I am extending the JSTL view class to implement my own view resolver. But, I am having the problem. Look into my code:
public class TestView extends JstlView {
private String fo_suffix = "_jo";
public void setUrl(String url)
{
//We need to change the inputed url to add a prefix for fo
super.setUrl(url.replace("\\.jsp", fo_suffix+ ".jsp"));
}
public void render(Map<String, ?> model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
final StringWriter xmlfo = new StringWriter();
HttpServletResponseWrapper wrapper = new HttpServletResponseWrapper(
response) {
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(xmlfo);
}
};
super.render(model, request, wrapper);
In the above code, when i am debugging, the control never comes to the setUrl method. So the url is always null in the internal RequestDispatcher.
Please help me to resolve the issue.

Dont forget to put TestView in "myServletName"-servlet.xml
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="test.TestView"/>
....

Related

login intercepter do not work in spring

all. i was using spring4 in my project. and add and interceptor extends HandlerInterceptorAdapter, then overwrite prehandle method. but i found it does not work when i was doing spring mock test.
i have configure it in springmvc-servlet.xml , like this:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.suerpay.common.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
and here is code of LoginInteceptor:
public class LoginInterceptor extends HandlerInterceptorAdapter {
#Autowired
LoginServiceRedis loginServiceRedis;
#Autowired
UserServiceDB userServiceDB;
Logger logger = LoggerFactory.getLogger(getClass());
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
logger.info("start login interceptor");
if (isLoginRequired(handler)) {
String ticket = request.getHeader(GlobalConstants.TICKET_HEADER);
if (StringUtils.isEmpty(ticket)) {
throw new UnAuthorizedException(ResultCodeConstants.USER_NOT_LOGIN);
}
String userName = loginServiceRedis.getUserNameByTicket(ticket);
Long userId = userServiceDB.getUserIdByName(userName);
if (null == userId) {
throw new UnAuthorizedException(ResultCodeConstants.USER_NOT_LOGIN);
}
ThreadContextHolder.setCurrentUserId(userId);
}
logger.info("finish login interceptor");
return true;
}
private boolean isLoginRequired(Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
LoginRequired loginRequired = method.getAnnotation(LoginRequired.class);
if (null != loginRequired) {
return true;
}
return false;
}
}
i think i have do everything , but just can not get into breakpoint.
who can tell me why?:(

Force 404 error when extension is added to URL

I need some help with URL mapping, in my code when i go to:
http://localhost:8080/register.asdf
http://localhost:8080/register.asddsdsd etc.
it always returns http://localhost:8080/register but I want to make it 404 NOT FOUND.
How can I fix this?
public class WebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(Config.class);
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
#Controller
public class UserController {
#RequestMapping(path = "/register", method = RequestMethod.GET)
public String registerGet(Model model) {
return "register";
}
EDIT : i added following code in Config.java and solved thanks.
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false);
}
You can restrict your mapping changin the #RequestMapping or the servlet.mapping.
Change RequestMapping:
#RequestMapping(path = "/register.htm", method = RequestMethod.GET)//for example
Or servlet.mapping:
servlet.addMapping("*.htm");
EDIT:
If you are using Spring 4.X you can use this:
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false" />
</mvc:annotation-driven>
From docs use below config to restrict the unwanted extensions
<mvc:annotation-driven>
<mvc:path-matching suffix-pattern="false" />
</mvc:annotation-driven>

Multiple Render and Action methods in Spring MVC portlet in Liferay

I'm creating a portlet which will take user name in form and display message Welcome in the same portlet after submission of form. For this I've used params in render method.
Note: I'm using spring-MVC with liferay 6.2.
The problem is when I submit name, it redirects to the same page instead of calling another render method.
Here is my view.jsp:
<portlet:actionURL var="actionOneMethodURL">
<portlet:param name="action" value="getUserName">
</portlet:param>
</portlet:actionURL>
<form action="${actionOneMethodURL}" method="post">
Enter Your Name:
<input type="text" name="userName" />
<input type="submit" value="OK!" />
</form>
Here is controller code:
public class PortletController implements Controller {
private static final String WELCOME_PAGE = "welcomeUser";
public void handleActionRequest(ActionRequest request,
ActionResponse response) throws Exception {
}
#ActionMapping(params = "action=getUserName")
public void actionOneMethod(ModelMap model, ActionRequest request,
ActionResponse response) {
String userName = request.getParameter("userName");
model.addAttribute("userName", userName);
response.setRenderParameter("action", "displayName");
}
#RenderMapping
public ModelAndView handleRenderRequest(RenderRequest request,
RenderResponse response) throws Exception {
Map<String, Object> model = new HashMap<String, Object>();
model.put("helloWorldMessage", "Hello There!");
return new ModelAndView("helloWorld", model);
}
#RenderMapping(params = "action=displayName")
public String displayName(ModelMap model, RenderRequest request,
RenderResponse response) throws Exception {
return WELCOME_PAGE;
}
}
Can someone help??
EDIT: Can this happen due to any xml file?? If so which one?
Here is part of code should work:
view.jsp : Name of this form should tell which one of the methods use in controller.
<portlet:actionURL name="actionOneMethod" var="actionOneMethodURL"/>
<form:form action="${actionOneMethodURL}">
<!-- your form body... -->
</form:form>
Controller.java : The one change I did is commented some handler method, and changed your action method to be used by its name. Rest looks fine.
public class PortletController implements Controller {
private static final String WELCOME_PAGE = "welcomeUser";
//I dont think you need this part at all...
/**public void handleActionRequest(ActionRequest request,
ActionResponse response) throws Exception {
}**/
#ActionMapping("actionOneMethod")
public void actionOneMethod(ModelMap model, ActionRequest request,
ActionResponse response) {
String userName = request.getParameter("userName");
model.addAttribute("userName", userName);
response.setRenderParameter("action", "displayName");
}
#RenderMapping
public ModelAndView handleRenderRequest(RenderRequest request,
RenderResponse response) throws Exception {
Map<String, Object> model = new HashMap<String, Object>();
model.put("helloWorldMessage", "Hello There!");
return new ModelAndView("helloWorld", model);
}
#RenderMapping(params = "action=displayName")
public String displayName(ModelMap model, RenderRequest request,
RenderResponse response) throws Exception {
return WELCOME_PAGE;
}
}
I assume you have correct view resolver configured. Here is part of in case:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
I think the part of commented method caused problem. Hope it helps.
I would guess that the problem may be with the param name. In the action try to set a different render parameter.
response.setRenderParameter("page","welcome")
Have a look here simple-spring-portlet

Spring autowired bean is null NULL

Why my beans is null?
[b]servlet-context.xml [/b]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
>
<!-- <context:annotation-config/>-->
<context:component-scan base-package="by"/>
<context:property-placeholder location="classpath:database.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/javakava"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</bean>
</beans>
[b]controller[/b]
public class Controller extends HttpServlet {
private static final long serialVersionUID = 1L;
#Autowired
private CommandFactory commandFactory;
#Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
performAction(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
performAction(request, response);
}
private void performAction(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String page = null;
String paramPage = request.getParameter(Constants.PARAM_PAGE);
try {
if (paramPage != null && !paramPage.isEmpty()) {
Command command = commandFactory.getCommand(paramPage);
page = command.execute(request);
// Commands c = Commands.valueOf(paramPage);
// Command command = c.getCommandClass().newInstance();
page = command.execute(request);
RequestDispatcher requestDispatcher = request
.getRequestDispatcher(page);
requestDispatcher.forward(request, response);
} else {
throw new IllegalAccessError(
"Error with access to class from Controller.java");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
LoginCommand - Here is autowared TestService bean. In IDEA it's look's good. But in debug mode my testService is null..
#Component
public class LoginCommand implements Command {
#Autowired
TestService testService;
public String execute(HttpServletRequest request) {
DaoCheckUserImpl id = new DaoCheckUserImpl();
String pass = request.getParameter(Constants.PASS);
String login = request.getParameter(Constants.LOGIN);
id.checkUser();
String userN = id.getUserN();
String userP = id.getUserP();
String userRole = id.getUserRole();
int userId = id.getUserId();
if (userN.equals(login) & userP.equals(pass) & userRole.equals("admin")) {
/*
*
* Here testService is null[/b]
*
*/
List<Test> tests = testService.getAllTests();
request.setAttribute(Constants.TESTS, tests);
User user = new User();
user.setLogin(login);
request.getSession().setAttribute(Constants.USER, user);
return Constants.MAIN_ADMIN_PAGE;
} else {
}
return Constants.ERROR_LOGIN_PAGE;
}
}
}
TestService
#Service
public class TestService {
#Autowired
public DaoTestImpl daoTestImpl;
public List<Test> getAllTests() {
return daoTestImpl.getAllTests();
}
public Test selectTest(String idTest) {
return daoTestImpl.selectTest(idTest);
}
public void deleteTest(Test test) {
daoTestImpl.deleteTest(test);
}
[b]DaoTestImpl [/b]
Here I using JdbcDaoSupport , datasource injected with constructor.
#Component
public class DaoTestImpl extends JdbcDaoSupport implements DaoTest {
#Autowired
public DaoTestImpl(DataSource dataSource) {
setDataSource(dataSource);
}
...
public List<Test> getAllTests() throws DAOException {
return getJdbcTemplate().query(("SELECT *FROM tests"), rowMapper);
}
CommandFactory
#Component
public class CommandFactory {
#Autowired
public LoginCommand loginCommand;
public Command getCommand(String paramPage) {
Commands command = Commands.valueOf(paramPage.toUpperCase());
switch (command) {
case LOGIN_COMMAND:
return loginCommand;
commands
public enum Commands { LOGIN_COMMAND
/*login_Command(LoginCommand.class),
How do you create LoginCommand object?
Autowired is used by Spring to inject the correct bean. So it works only if LoginCommand is created by Spring. If you performed a NEW, or if you use another framework without a proper integration with Spring, this can explain your issue (for example Jersey 2 without the proper configuration).
EDIT:
By the way, you can had "#Required" annotation. This will not fix your problem, but the new error message can help you to understqnd what happen (in particular it will help to see if LoginCommand object is really created by Spring and if the autowired failed [as I think] because the instance of TestService was NOT found [package naming issue, classloader issue, etc.])
Did you check if all your components are in the "by" package (that is specified in component-scan)?

Stream directly to response output stream in handler method of Spring MVC 3.1 controller

I have a controller method that handles ajax calls and returns JSON. I am using the JSON library from json.org to create the JSON.
I could do the following:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public String getJson()
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson.toString();
}
But it is inefficient to put together the JSON string, only to have Spring write it to the response's output stream.
Instead, I can write it directly to the response output stream like this:
#RequestMapping(method = RequestMethod.POST)
public void getJson(HttpServletResponse response)
{
JSONObject rootJson = new JSONObject();
// Populate JSON
rootJson.write(response.getWriter());
}
But it seems like there would be a better way to do this than having to resort to passing the HttpServletResponse into the handler method.
Is there another class or interface that can be returned from the handler method that I can use, along with the #ResponseBody annotation?
You can have the Output Stream or the Writer as an parameter of your controller method.
#RequestMapping(method = RequestMethod.POST)
public void getJson(Writer responseWriter) {
JSONObject rootJson = new JSONObject();
rootJson.write(responseWriter);
}
#see Spring Reference Documentation 3.1 Chapter 16.3.3.1 Supported method argument types
p.s. I feel that using OutputStream or Writer as an parameter is still much more easier to use in tests than a HttpServletResponse - and thanks for paying attention to what I have written ;-)
In the end, I wrote an HttpMessageConverter for this. With it, I can do the following:
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public JSONObject getJson()
throws JSONException
{
JSONObject rootJson = new JSONObject();
// Populate JSON
return rootJson;
}
Here is my HttpMessageConverter class:
package com.example;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
public class JsonObjectHttpMessageConverter
extends AbstractHttpMessageConverter<JSONObject>
{
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public JsonObjectHttpMessageConverter()
{
super(new MediaType("application", "json"), new MediaType("text", "javascript"));
}
#Override
protected boolean supports(Class<?> clazz)
{
return JSONObject.class.equals(clazz);
}
#Override
protected JSONObject readInternal(Class<? extends JSONObject> clazz,
HttpInputMessage inputMessage)
throws IOException,
HttpMessageNotReadableException
{
throw new UnsupportedOperationException();
}
#Override
protected void writeInternal(JSONObject jsonObject,
HttpOutputMessage outputMessage)
throws IOException,
HttpMessageNotWritableException
{
PrintWriter writer = new PrintWriter(new OutputStreamWriter(outputMessage.getBody(),
getContentTypeCharset(outputMessage)));
try
{
jsonObject.write(writer);
writer.flush();
}
catch (JSONException e)
{
throw new HttpMessageNotWritableException(e.getMessage(), e);
}
}
private Charset getContentTypeCharset(HttpMessage message)
{
MediaType contentType = message.getHeaders().getContentType();
Charset charset = (contentType != null) ? contentType.getCharSet() : null;
return (charset != null) ? charset : DEFAULT_CHARSET;
}
}
The HttpMessageConverter must be registered with Spring. This can be done in the dispatcher-servlet.xml file like this:
<beans ...>
...
<mvc:annotation-driven conversion-service="conversionService" validator="validator">
<mvc:argument-resolvers>
...
</mvc:argument-resolvers>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/plain;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
<value>*/*</value>
</list>
</property>
<property name="writeAcceptCharset" value="false" />
</bean>
<bean class="com.example.JsonObjectHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
...
</beans>
As you can see, I have other HttpMessageConverter objects registered too. The order does matter.
Note that if you use the OutputStream or Writer it requires you to write the headers yourself.
One workaround is to use InputStreamResource/ResourceHttpMessageConverter

Resources