Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
919 views
in Technique[技术] by (71.8m points)

jsf 2 - How to add cookie in JSF?

When I add a cookie as below:

FacesContext.getCurrentInstance().getExternalContext().addResponseCookie("Test", "Test", null);

Then it works well, but the cookie becomes a session cookie with max age of -1.

When I try as below:

Map<String, Object> properties = new HashMap<>();
properties.put("domain", "test");
properties.put("maxAge", 31536000);
properties.put("secure", false); 
properties.put("path","/");
FacesContext.getCurrentInstance().getExternalContext().addResponseCookie("Test", "Test", properties);

Then I don't see the cookie anywhere. I don't understand why.

I'm using Tomcat 7.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your specific case failed because the domain was set wrongly. Cookies are domain specific. You can't set a cookie on a different domain. If you don't specify the domain, then it will default to the domain of the current request URI. The Cookie#setDomain() is only useful if you intend to set a cookie on a common or different subdomain. E.g. if you have foo.example.com and bar.example.com, then you could set cookies for the other domain via that method, or set the domain to .example.com (with the leading period!) to share the cookie between both subdomains.

So, this should do in your particular case:

String name = "cookiename";
String value = "cookievalue";
Map<String, Object> properties = new HashMap<>();
properties.put("maxAge", 31536000);
properties.put("path", "/");
externalContext.addResponseCookie(name, URLEncoder.encode(value, "UTF-8"), properties);

Note that explicitly setting the path is very important in case you intend to use the cookie webapp-wide, as it otherwise defaults to the current path which would of course fail when it's set for first time in a subfolder. Such a cookie won't be accessible in any parent folder. The other answer here above doesn't properly take this into account as it unnecessarily and incorrectly reuses an existing cookie instead of creating it brand new. See also a.o. In Java servlet, cookie.getMaxAge() always returns -1.

As to retrieving a cookie in JSF, use ExternalContext#getRequestCookieMap():

Cookie cookie = (Cookie) externalContext.getRequestCookieMap().get(name);
String value = URLDecoder.decode(cookie.getValue(), "UTF-8");
// ...

Note that I'm URL-encoding/decoding the cookie value before setting/retrieving, as you would otherwise run into trouble like asked in the following related questions: Why do cookie values with whitespace arrive at the client side with quotes? and java.lang.IllegalArgumentException: Control character in cookie value or attribute.

That said, I do agree that the JSF API is somewhat opaque as to retrieving and setting cookies. The JSF utility library OmniFaces has several useful utility methods in the Faces utility class for the purpose, which implicitly sets sane defaults as cookie properties and URL-encodes/decodes the value.

// Getting a cookie value.
String value = Faces.getRequestCookie(name);

// Setting a session cookie in current path.
Faces.addResponseCookie(name, value, -1);

// Setting a session cookie in current domain.
Faces.addResponseCookie(name, value, "/", -1);

// Setting a (sub)domain-wide session cookie.
Faces.addResponseCookie(name, value, ".example.com", "/", -1);

// Setting a cookie with max age of 1 year in current domain.
Faces.addResponseCookie(name, value, "/", (int) TimeUnit.DAYS.toSeconds(365));

// Removing a cookie from current domain.
Faces.removeResponseCookie(name, "/");

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...