问题
This has been driving me nuts.
So I have a (very simple vanilla servlet 3) web app. When I run it in eclipse all is fine. Among others I am able to register an account with Unicode (greek) username and then log in as site admin and visit the user's profile alright. When I export war to $CATALINA_HOME\webapps
, launch $CATALINA_HOME\bin\startup.bat
, open the site in the browser, login as admin and try to visit the user profile the username etc display as blank.
The files in ...\apache-tomcat-7.0.32\conf
and the ones in ...\eclipse_workspaces\javaEE\Servers\Tomcat v7.0 Server at localhost-config
differ only in the line (in server.xml
) :
<Context docBase="ted2012" path="/ted2012" reloadable="true"
source="org.eclipse.jst.jee.server:ted2012"/>
which is an eclipse thing.
The doGet method (slimmed) in the profile servlet :
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
final String username = Helpers.decodeRequest(request
.getParameter("user"));
if (username != null) {
User user = null;
try {
System.out
.println("ProfileController.doGet() user name DECODED : "
+ username);
user = userService.getUserWithUsername(username); // THIS FAILS
System.out.println("ProfileController.doGet() user : " + user);
request.setAttribute("userToShow", user);
} catch (ServiceExDBFailure e) {
log.debug("ProfileController::doGet", e);
request.setAttribute("ErrorString", e.getMessage());
}
sc.getRequestDispatcher(OTHERPROFILE_JSP)
.forward(request, response);
return;
} else {
//does not apply
}
}
The decode method is :
public static String decodeRequest(String parameter)
throws UnsupportedEncodingException {
if (parameter == null)
return null;
System.out.println("decode - request.getBytes(\"iso-8859-1\"):"
+ new String(parameter.getBytes("iso-8859-1")));
System.out.println("decode - request.getBytes(\"iso-8859-1\") BYTES:"
+ parameter.getBytes("iso-8859-1"));
for (byte iterable_element : parameter.getBytes("iso-8859-1")) {
System.out.println(iterable_element);
}
System.out.println("decode - request.getBytes(\"UTF-8\"):"
+ new String(parameter.getBytes(CHARSET_FOR_URL_ENCODING))); // UTF-8
return URLDecoder.decode(new String(parameter.getBytes("iso-8859-1")),
CHARSET_FOR_URL_ENCODING);
}
While the db call is :
statement = conn.prepareStatement(query);
statement.setString(1, username);
System.out.println("ελληναρα");
System.out.println(statement);
set = statement.executeQuery();
if (set.next()) {
User user = new User();
// user.setId(set.getInt("ID"));
user.setUsername(set.getString("username"));
user.setName(set.getString("name"));
user.setSurname(set.getString("surname"));
user.setPassword(set.getString("password"));
user.setEmail(set.getString("email"));
user.setRole(RolesENUM.values()[set.getInt("role")]);
return user; // if the set is empty null is returned
}
Tomcat prints :
decode - request.getBytes("iso-8859-1"):╧à╧â╧ä╬╡╧?╬╣╬▒
decode - request.getBytes("iso-8859-1") BYTES:[B@529b9ed
-49
-123
-49
-125
-49
-124
-50
-75
-49
-127
-50
-71
-50
-79
decode - request.getBytes("UTF-8"):├?┬à├?┬â├?┬ä├Ä┬╡├?┬?├Ä┬╣├Ä┬▒
ProfileController.doGet() user name DECODED : ╧à╧â╧ä╬╡╧?╬╣╬▒
com.mysql.jdbc.JDBC4PreparedStatement@766d7940: SELECT * FROM users WHERE username='╧à╧â╧ä╬╡╧?╬╣╬▒'
????????
ProfileController.doGet() user : null
while Eclipse prints :
decode - request.getBytes("iso-8859-1"):υστερια
decode - request.getBytes("iso-8859-1") BYTES:[B@4b6a6bdf
-49
-123
-49
-125
-49
-124
-50
-75
-49
-127
-50
-71
-50
-79
decode - request.getBytes("UTF-8"):ÏÏÏεÏια
ProfileController.doGet() user name DECODED : υστερια
com.mysql.jdbc.JDBC4PreparedStatement@37d02427: SELECT * FROM users WHERE username='υστερια'
ελληναρα
ProfileController.doGet() user : com.ted.domain.User@63144ceb
I believe for some reason the query that gets to the db is something crazy - notice that where in eclipse prints ελληναρα in tomcat prints ???????? while the unicode username (υστερια) prints as ╧à╧â╧ä╬╡╧?╬╣╬▒ and not as ???????.
So the question is - what changes between the Eclipse deployment and the tomcat deployment ? Why the hell the DB returns null ? I have really really tried to debug this in vain
Help
EDIT : replacing the line statement.setString(1, username);
with statement.setString(1, "υστερια");
there is NO failure. So by the time this line is run the bytes are mangled up - notice though that the bytes are the same one by one
EDIT2 : Tomcat v7.0 Server at localhost Eclipse launch VM args (split for readability) :
-Dcatalina.base="C:\Dropbox\eclipse_workspaces\javaEE\.metadata\.plugins
\org.eclipse.wst.server.core\tmp1"
-Dcatalina.home="C:\_\apache-tomcat-7.0.32"
-Dwtp.deploy="C:\Dropbox\eclipse_workspaces\javaEE\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps"
-Djava.endorsed.dirs="C:\_\apache-tomcat-7.0.32\endorsed"
NB : the launch for the app is created dynamically
EDIT 2013.03.30 : this is now on github - and see my more general question here
回答1:
This was finally answered here.
The gist of the answer is that I eclipse had as default encoding UTF-8 and Tomcat windows-1252
so when I call new String() without specifying the encoding those are used to tranlate the byte[] to chars. Doing
new String(parameter.getBytes("iso-8859-1"), "UTF-8");
solves the problem - it would not though if tomcat in
request.getParameter("user") // url decoding is performed by tomcat - using the
// URIEncoding from server.xml or by default ISO-8859
would not use by default ISO-8859 as another encoding (say ASCII) would probably (behavior undefined and not controllable before Java 7 nio) replace undecodable characters with ?
so parameter
String would be corrupted (see ISO-8859-1 encoding and binary data preservation).
So bravo to tomcat for performing the conversion by default with ISO-8859 in its request.getParameter()
and boo to Java ee spec guys who do not even mention in the docs that getParameter will perform URL decoding, let alone letting us specify the encoding, overriding server.xml.
来源:https://stackoverflow.com/questions/14914983/webapp-behaves-as-expected-when-run-from-eclipse-while-when-exported-as-war-fail