spring mvc path variables encoding - java

I am using spring mvc. I am surfing to:
http://localhost:8080/services/cities/פת.html
notice that פת is in hebrew and not english.
My controller is:
#RequestMapping(value="/services/cities/{name}", method=RequestMethod.GET)
public #ResponseBody List<SelectElement> getCities(#PathVariable String name) {
List<SelectElement> elements=null;
...
...
return elements;
}
The problem is that the controller receives פת and not the correct characters.
How can I fix it?
Even if I surfing to: http://localhost:8080/services/cities/%D7%A4%D7%AA.html I get this problem.

If you are using tomcat, then you have to specify the URL encoding for requests by adding URIEncoding="UTF-8" on <Connector> in the Tomcat server.xml config, as described here:
http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q8

Here you have an interesting documentation about encoding requests in Tomcat
Something like CharacterEncodingFilter will only work in POST requests. You need to change Tomcat (or another container) configuration in order to use an URI enconding different from ISO-8859-1. But this won't work in all browsers, it depends on how they encode the URI too.
So my recommendation is always use simplest characters as possible. If you tell us what are you trying to achieve maybe we can find some better solution (I suppose you don't need the user too type the name of the city directly in address bar).

Use the CharacterEncodingFilter filter...
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>

Related

Spring mvc filter doesn't take effect

I'm learning SpringMVC. The version I use is 4.2.5.RELEASE. The filter I configure in web.xml doesn't seem to work
Server: Tomcat 7
Problem : When I use the GET method to pass in Chinese parameters, even if I configure the filter for UTF-8 encoding conversion, but the string I get is still garbled
web.xml:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I consider my configuration is not wrong
Controller:
#RequestMapping(value = "/user/info", method = RequestMethod.GET)
public String getInfo(HttpServletRequest request,
#RequestParam("username") String username, Model model) {
UserInfo userInfo = new UserInfo(username, "xxx", "xxx");
Logger.i(userInfo.toString());
model.addAttribute("info", userInfo);
return "user/info";
}
When I pass in the Chinese parameters, the information printed by the console is garbled, and it is garbled to return to the front.
And request.getCharacterEncoding() return is "UTF-8"
But when i use:
try {
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
It can display normally.
So I changed the default encoding of Tomcat and changed it to UTF-8. After that, even if I don't perform transcoding in the code, I can get the correct parameters.
Question: So I am very puzzled that the filter has no effect.
I would like to express my heartfelt thanks for your enthusiasm. Thanks!
Have you tried configuring Tomcat's server.xml? Try setting URIEncoding="UTF-8" attribute to a Connector component:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
URIencoding="UTF-8"
redirectPort="8443" />
You can get more information here

What's the difference between "URIEncoding" of Tomcat, Encoding Filter and request.setCharacterEncoding

There may be many ways to solve encoding problem:
Encoding filter like Spring MVC UTF-8 Encoding
Setting URIEncoding=UTF-8 in server.xml of Tomcat , like http://struts.apache.org/release/2.1.x/docs/how-to-support-utf-8-uriencoding-with-tomcat.html.
request.setCharacterEncoding( utf-8 )
Today, I have a problem that path param is not decoded well like
#ResponseBody
#RequestMapping(value="/context/method/{key}",method=RequestMethod.GET,produces = "application/json;charset=utf-8")
public String method(#PathVariable String key){
logger.info("key="+key+"------------");
}
I can see that the key is decoded bad! If I pass a word "新浪" from the front end, it will become "æ°æµª". I write the below code to examine if the server is decoding this with "ISO-8859-1":
public static void main(String args[]) throws UnsupportedEncodingException{
String key="新浪";
byte[] bytes=key.getBytes("UTF-8");
String decode=new String(bytes,"ISO-8859-1");
System.out.println(decode);
}
And it comes out with the same output "æ°æµª". so indeed, the path variable is decoded with ISO-8859-1.
And then I try to add a filter to my web.xml to solve this problem:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
But the same garbled.
Until I set below to my server.xml
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"
URIEncoding="UTF-8" useBodyEncodingForURI="true" ----Here is Added
/>
And it works for this even I remove the filter.
But I am still very confusing about the encoding issue. And besides , this is only GET method, if it is POST method, I guess the solution will probably be different
Can anybody please explain that what difference encoding solution should we take for what kind of problem ?
Thank you!
CharacterEncodingFilter configures encoding of request body. That is, it affects encoding of POST request parameters, etc, but doesn't affect encoding of GET parameters
URIEncoding is used to specify encoding of the URI, therefore it affects GET parameters
useBodyEncodingForURI="true" tells Tomcat to use encoding configured for request body when decoding URIs. So, as far as I understand, if you set CharacterEncodingFilter and useBodyEncodingForURI="true" then you don't need URIEncoding.
In practice, you need to two things to solve possible problems with encoding of parameters:
CharacterEncodingFilter for POST requests
URIEncoding (or useBodyEncodingForURI="true") for GET requests
for tomcat7
CharacterEncodingFilter configures encoding of request body. That is, it affects encoding of POST request parameters, etc, but doesn't affect encoding of GET parameters
useBodyEncodingForURI="true" tell tomcat to use CharacterEncoding( can be set by CharacterEncodingFilter) to parse QueryString. it's affect GET request parameter .
URIEncoding to parset URI , default is ISO-8859-1.
for tomcat8
default UTF-8.

Is there a way to change the output type for restful webservices by a parameter in java?

I wanna use the same restful webservice path to produce xml or json, or a xml with xsl header.
Is it possible using any framework(jersey or resteasy) in java?
Eg:
#Path("/person")
public class PersonService {
#GET
#Path("/find")
public Person find(#QueryParam("name") String name, #QueryParam("outputformat") String outputformat) {
// do some magic to change output format
return dao.findPerson(name);
}
}
Maybe you can write a servlet filter that takes the query string and uses it to set the request's accept header accordingly, then jersey should dispatch to whatever method is annotated with #Consumes that matches.
For example, servlet filter intercepts request "?outputFormat=xml" and sets the Accept header to "application/xml". Then, jersey should dispatch to whichever method in your resource is annotated with: #Consumes("application/xml")
This question might help: REST. Jersey. How to programmatically choose what type to return: JSON or XML?
You could also easily customize Jersey ServletContainer and you won't require another param to pass along. You could negotiate representation using .json or .xml in your URL.
public class MyServletContainer extends ServletContainer {
#Override
protected void configure(ServletConfig servletConfig, ResourceConfig resourceConfig, WebApplication webApplication) {
super.configure(servletConfig, resourceConfig, webApplication);
resourceConfig.getMediaTypeMappings().put("json", MediaType.APPLICATION_JSON_TYPE);
resourceConfig.getMediaTypeMappings().put("xml", MediaType.APPLICATION_XML_TYPE);
}
}
In your web.xml, you could define the custom servlet as shown below.
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>com.sun.jersey.MyServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.sun.jersey.MyWebApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
You could use Jersey and use the annotation #Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}). You would need to add a mapping feature for POJOs in your application as well. The include in the web.xml file would be
<filter>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
</filter>
Other configurations would be necessary, but it is all in the documentation http://jersey.java.net/nonav/documentation/latest/user-guide.html

How to allow access to static content when having default servlet

I map all requests to /* to a specific servlet.
My static content is hidden by this configuration.
How can i allow access to specific files (such as crossdomain.xml)?
When you map /* to a specific servlet, all requests will be forwarded to that servlet, unless you provide a more explicit mapping to another servlet.
That is, if you have /* mapped to ServletA, and /static/* mapped to ServletB, then following Servlets will get called.
http://localhost:8080/abc.jpg -> ServletA
http://localhost:8080/static/abc.jpg -> ServletB
http://localhost:8080/xyz/abc.jpg -> ServletA
So one option you have is to write a Servlet to handle the static content, which will grab the file and return it as response. You can map that servlet to a prefixed by something like /static/*. This requires that all URL references to your static files to be updated to contain this '/static' part.
If that is not feasible for you, then probably you can use the same servlet, but mapped to multiple URL patterns (probably by extension) as follows.
<servlet>
<servlet-name>static-servlet</servlet-name>
<servlet-class>xxx.yyy.StaticServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>static-servlet</servlet-name>
<url-pattern>*.xml</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>static-servlet</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
If you want this to be fine-grained to the level of each file, you can map the servlet to your file URL as well.
Cookbook:
Map your controller Servlet on a more specific url-pattern like /app/*.
Put all the static content in a specific folder like /static.
Create a Filter which is mapped on /* which transparently continues the chain for any /static requests and dispatches other requests to /app.
So, in a nutshell:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/pages/*</url-pattern>
</servlet-mapping>
with the following in filter's doFilter():
String uri = ((HttpServletRequest) request).getRequestURI();
if (uri.startsWith("/static/")) {
chain.doFilter(request, response); // Goes to default servlet.
} else {
request.getRequestDispatcher("/app" + uri).forward(request, response);
}
No, you do not end up with extra /app path in the URL. It's fully transparent. Make if necessary "/static" and/or "/app" an <init-param> of the filter.
And one more(a direct) servlet mapping like this<servlet-mapping><servlet-name>StaticContentServlet</servlet-name><url-pattern>/crossdomain.xml</url-pattern></servlet-mapping>
probably you can put your static content under different URL like /static/* and then map this URL to a Servlet which responds with the static content.

Accessing context parameters within Servlet Filters

Thanks to everyone in advance,
I am trying to access any context parameters in the web.xml from within a servlet filter. Below is a portion from my web.xml file. I have verified that the context-param node is accessible via a jsp page using out.print(getServletContext().getInitParameter("error"));.
<filter>
<filter-name>prePost</filter-name>
<filter-class>MyFilter</filter-class>
<init_param>
<param_name>error</param_name>
<param_value>/test.jsp</param_value>
</init_param>
<filter-mapping>
<filter-name>prePost</filter-name>
<url-pattern>*.jsp</url-pattern>
<context-param>
<description>Error Handler</description>
<param-name>error</param-name>
<param-value>/test.jsp</param-value>
In my filters doFilter when I output this.filterConfig.getInitParameter("error"), I always get null. In my filters init() I am setting this.filterConfig with the passed in FilterConfig.
Thanks,
Sam
You're using underscores rather than hyphens for "param-name" and "param-value". Your config should look like this:
<init-param>
<param-name>error</param-name>
<param-value>/test.jsp</param-value>
</init-param>

Categories

Resources