I currently have the following:
cartServlet.java
public class CartServlet extends HttpServlet{
private static final long serialVersionUID = 1L;
CartBean cartBean = new CartBean();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int counter = 0;
while (request.getParameterMap().containsKey("id" + counter)){
String songID = request.getParameter("id" + counter);
cartBean.setCartInfo(songID);
++counter;
}
request.setAttribute("cart", cartBean);
RequestDispatcher rd = request.getRequestDispatcher("/cart.jsp");
rd.forward(request, response);
}
cart.jsp
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Shopping Cart</title>
</head>
<body>
"${cart.cartInfo}"
</body>
</html>
cartBean.java
public class CartBean implements Serializable {
private static final long serialVersionUID = 1L;
private List<String> cart;
public CartBean(){
cart = new ArrayList<String>();
}
public void setCartInfo(String cartItem) {
this.cart.add(cartItem);
}
public List<String> getCartInfo() {
return cart;
}
}
When I print "${cart.cartInfo}", my output is coming out like this:
"[381d3af3-c113-46c1-b9d0-2c46cf445e22}, 3913ac54-0c03-4025-8279-5cfad2fcab5f}, 50ed6861-f6e2-479b-865c-cbbbc5c27efd}, eb9b29d6-d93e-4cd8-8d7a-7fe26ff6c05d}]"
Is this the correct way the output should be printed out? I don't know why the additional } is appearing at the end of each item..
Also, should I be defining CartBean cartBean = new CartBean(); in cartServlet.java? If a user were to come back to this shopping cart page and select more items, would the new items be placed in a different bean to the one I was originally using?
Thanks for your help.
Is this the correct way the output should be printed out? I don't know
why the additional } is appearing at the end of each item..
I'm guessing that yes, what's being listed on your JSP is what's supposed to be listed. Now it may differ from what you want, which is another matter. What appears to be currently listed is the ID for a song. In this XML file, I see one of the IDs listed as for "The Sweetest Taboo" by Sade in this homework file: http://www.cse.unsw.edu.au/~cs9321/14s1/assignments/musicDb.xml.
You need to use the useBean tag in your JSP. The syntax is as follows:
<jsp:useBean id = "idName" class = "packageName.SpecificClass" scope = "desiredScope" />
Fill in id, class, and scope with the desired values. The most common value for scope seems to be session.
Then set the property:
<jsp:setProperty name = "idName" property = "*" />
For more information about setProperty (along with useBean), see: jsp:setproperty what does property="*" mean?.
Also, should I be defining CartBean cartBean = new CartBean(); in
cartServlet.java?
It's usually best to use the servlet for the bean, especially if there's some processing that's going on, like filling in lists. Avoid putting a lot of Java code in your JSPs. The JSP should be able to grab a list of products and place them on the page, but it should not be able to instantiate the list, populate it, massage it into the form you need, and then place the products.
If a user were to come back to this shopping cart
page and select more items, would the new items be placed in a
different bean to the one I was originally using?
Read this page: http://www.jguru.com/faq/view.jsp?EID=53309.
You need to put the statement of creating CartBean inside doPost() method as a local variable, otherwise each request will create a new Thread and these threads share the instance variable which means the data in CartBean will be corrupted by different users.
Related
I want to implement an i18n-support for a wicket 7 application.
Requirements:
Translations must be easily editable by the admin-user
Translations must take place without redeployment
My actual apporach is to hold the translations inside a DB. All translations will be cached. If a translation is changed by a Frontend-task the cache and the db will be updated.
So far so easy.
Actually I'm stuck in replacing the translations inside a page.
A working solution would be loading every translation during implementation. These translations would be set inside many of wicket-elements.
I don't like this approach, because it'll mess up the code (html + java) heavily.
I'll try to implement a replacement-mechanism in my actual approach. After the page is rendered, the mechanism is run through the whole page and is doing these jobs:
search for all placeholders
load the translation for the placeholder-keys(cache)
replace the placeholders with the translations
This should work for body and header (site's title)
Here is an example of a wicket-template
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${landingpage.site.title}</title>
</head>
<body>
<header wicket:id="headerPanel">header</header>
${welcome.message}
<footer wicket:id="footerPanel">footer</footer>
</body>
</html>
In this case ${landingpage.site.title} and ${welcome.message} should be recognized and replaced. As you can see it is directly definied inside the template, not in the java-code. And this is what I want to achieve.
I hope I made the requirements clear enough. If not, don't mind to comment. I'll update the question to make it more clear.
My approach is to implement a BasePage (extends Page) and overwrite the onAfterRender-Method
#Override
protected void onAfterRender() {
super.onAfterRender();
Response originalResponse = RequestCycle.get().getResponse();
String updatedResponse = replaceWithTranslations(originalResponse);
originalResponse.reset();
originalResponse.write(updatedResponse);
}
The method replaceWithTranslations is not yet implemented and returns a simple String actually. This method should convert the outputstream of the originalRepsonse to a String, searches for placeholders and replace them with the values of the db.
This approach seems to have 2 difficulties:
I'm not getting the response as String
I'm getting a WicketRuntimeException (Page.checkRendering in Page.java:666)
Any advice would be great!
OK, the problems seems to be a very simple one.
The trick or the luck is, here we have a BufferedWebResponse. A simple cast will do the trick:
#Override
protected void onAfterRender() {
super.onAfterRender();
BufferedWebResponse originalResponse = (BufferedWebResponse) RequestCycle.get().getResponse();
String translatedResponse = replaceWithTranslations(originalResponse);
originalResponse.reset();
originalResponse.write(translatedResponse);
}
private String replaceWithTranslations(BufferedWebResponse originalResponse) {
String untranslatedText = originalResponse.getText().toString();
String translatedText = doTheTranslation(untranslatedText);
return translatedText;
}
Inspired by #RobAu I gave the wicket's approach of i18n a chance. Here is with what I came up with:
The template:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><wicket:message key="landingpage.site.title">Site-Title</wicket:message></title>
</head>
<body>
<header wicket:id="headerPanel">header</header>
<wicket:message key="welcome.message">Welcome</wicket:message>
<footer wicket:id="footerPanel">footer</footer>
</body>
</html>
wicket:message for attributes:
<input type="text" placeholder="username" wicket:message="placeholder:login.username"/>
The IStringResourceLoader:
#org.springframework.stereotype.Component
public class I18NResourceLoader implements IStringResourceLoader {
#Autowired
private I18NCache i18nCache;
#Override
public String loadStringResource(final Class<?> clazz, final String key, final Locale locale, final String style, final String variation) {
return loadTranslation(key, locale);
}
#Override
public String loadStringResource(final Component component, final String key, final Locale locale, final String style, final String variation) {
return loadTranslation(key, locale);
}
private String loadTranslation(final String key, final Locale locale) {
final Optional<Translation> optional = i18nCache.get(key, locale);
if (!optional.isPresent()) {
return key;
}
return optional.get().getText();
}
}
Translation and I18NCache are self-implemented classes.
And finally the registration:
public abstract class BasePage extends WebPage {
#SpringBean
private I18NResourceLoader i18NResourceLoader;
public BasePage(){
addI18NResourceLoader();
...
}
private void addI18NResourceLoader() {
final List<IStringResourceLoader> resourceLoaders = Application.get().getResourceSettings().getStringResourceLoaders();
final boolean existsResourceLoader = resourceLoaders.stream()
.filter(p -> p instanceof I18NResourceLoader)
.collect(Collectors.counting()) > 0L;
if (!existsResourceLoader) {
resourceLoaders.add(i18NResourceLoader);
}
}
...
}
Pro's:
Wicket's approach
No mess with RegEx-Replacement-Handling
SPR
Con's
Template feels a little more messy
Actually, I have no informations about the performance of this approach.
I decided to keep the logic of adding the ResourceLoader in BasePage by 2 reasons.
BasePage is responsible for everything concering the page-representation (weak reason :-) )
I'm using DI. If I would add the logic in the WebApplication, I would have to manually inject the I18NResourceLoader or its dependencies.
I think you can extend IComponentResolver to replace the placeholders like WicketMessageResolver.
First sorry for my english...
I was searching for all internet but I can't find the answer of my question. I tried everything, looked in documentation, tutorials, videos, etc...
I put two buttons in the top of my page for the user can change the language, but I can't catch the value on my controller, I did everything but never can handle. I'm new on play :( please help...!!
I have this on my view:
<`form method="GET" action="#{Application.language("value")}"/`>
<`input> name="language" type="submit" value="en" title="#Messages("button.en")" </`>
<`input> name="language" type="submit" value="es" title="#Messages("button.es")" </`>
<`/form`>
And this on my controller:
public static void language(String idiom) {
String key = null;
key = idiom;
if(key.isEmpty()){
} else {
Lang.apply(idiom);
}
}
But when I try to catch the value on my controller always I received this message:
[RuntimeException: Unrecognized language: value]
Your HTML looks a little suspect, can you clean it up and repost along with your controller and route?
In the meanwhile, this is roughly what I'd expect to see to make sure your parameters get passed in properly:
Routes:
GET /language #controllers.LanguageController.index(language: String)
Controller:
LanguageController {
...
public Result index(String language) {
if(language != null && !language.isEmpty()){
Lang.apply(idiom);
}
... return
}
}
To make the setting stick in Play 2, see this post
playframework 2.2 java: how to set language (i18n) from subdomain
I did it a little modification with your comment below and this is how I have now.
Route:
POST / #controllers.LanguageController.changeLanguage(language: String)
View:
<form method="POST" action="changeLanguage("value")"/>
<input name="language" type="submit" value="en" title="English" </>
<input name="language" type="submit" value="es" title="Spanish" </>
</form>
Controller:
public class LanguageController extends Controller{
public Result changeLanguage(String language)
{
if(language != null && !language.isEmpty())
{
Lang.apply("en");
}
else
{
String idiom = language;
Lang.apply(idiom);
}
return ok(index.render(""));
}
Now I have this message error:
For request 'POST /changeLanguage(value)'
And the page error shows the route of the LanguageController this:
POST/#controllers.LanguageController#.changeLanguage(language:String)
You have messages.{lang} ( like messages.es or messages.en) in conf folder right?
And in application.conf valid langs should exist like;
application.langs="en,es"
If you have these so in any class which extends Controller you can run this method;
changeLang("es");
But in your case it seems that value of the idiom in your function is "value"
So if it's fine for you just replace the form header as;
<form method="GET" action="/language"/>
(assuming that /language will route to your method)
and replace the names of the html inputs as "idiom"
so you will be passing the right value of the input.
In play 2.8, Http.Context was deprecated which lead to changes in the interaction with the response object.
To change the language you need to do the following:
Inject an instance of MessagesApi into your controller
Create an instance of Lang object with the language you intend to use
Use method .withLang(Locale locale, MessagesApi messagesApi) on your result object
Code to illustrate:
private final MessagesApi messagesApi;
#Inject
public LoginController(MessagesApi messagesApi) {
this.messagesApi = messagesApi;
}
// ... now in the method invoked by the router
Lang lang = Lang.apply("en"); //english language
return ok().withLang(lang.toLocale(), messagesApi);
This changes the language throughout the rest of the session, since play will store the language in the cookie PLAY_SESSION. If you want to change only for one particular request, you must change the request object instead of the result object.
Reference here
I am using Primefaces/JSF in combination with pure javascript tools in order to implement an image viewer & annotator. Image viewer is built upon the OpenLayers framework.
When the user annotates (draws shapes) on the canvas, a JSON object is created and upon Save action passed to the back bean. Back bean retrieves the object (deserialized) and stores it in to a file.
Here is the relevant code:
OpenLayers javascript (image-viewer.js):
function initialiseMap(){'
...
map = new OpenLayers.Map(imageEditorID, options);
imageLayer = new OpenLayers.Layer.TMS(imgURL, "", {
...
});
map.addLayer(imageLayer);
var vlayer = new OpenLayers.Layer.Vector("Editable");
map.addLayer(vlayer);
//draw controls and shape tools
...
//then define save action
var save = new OpenLayers.Control.Button({
...
var GEOJSON_PARSER = new OpenLayers.Format.GeoJSON();
var vectorLayerAsJson = GEOJSON_PARSER.write(vlayer.features);
//and finally post to server layer with drawn shapes
sendJSONToServer([{name:'param', value:vectorLayerAsJson}]);
...
The above Image Viewer/Map tool, is loaded via an p:outputPanel component of primefaces and uses sendJSONToServer remoteCommand to get JSON layer:
<h:head>
<script src="#{facesContext.externalContext.requestContextPath}/js/image-viewer.js" />
...
<h:body>
<h:form id="imageEditor">
<p:fieldset legend="Viewer">
...
// inoutHidden does not have on* events? how am i going to post to image-viewer.js?
<h:inputHidden value="#{imageAnnotations.fetchJsonString()}" />
...
<p:outputPanel layout="block" styleClass="imageEditorImagePanel" />
<p:remoteCommand immediate="true" name="sendJSONToServer" action="#{imageAnnotations.actionOnString}" />
</p:fieldset>
....
Finally in the backbean the JSON object is fetched and stored in a file (implementation is raw):
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
//actionOnString fetches and saves the JSON string - this is a raw impementation
public String actionOnString() {
//Do the job and get and save JSON string
}
public String fetchJsonString(){
//Do the job and get JSON string
return jsonString;
}
}
The question is How am i going to use a JSF or primefaces element to make available the imageAnnotations.fetchJsonString() value for fetching from within js?
Even I can't give all answers, for me the filling of your hiddenInput should be managed as following:
#ManagedBean(name="imageAnnotations")
public class ImageAnnotations {
private String jsonString;
public void anyMethodFillingOrInitializingTheJSONString() {
this.jsonString = resultOfYourWork();
}
public String getJsonString(){
return this.jsonString();
}
public void setJsonString(String item) {
this.jsonString = item;
}
}
When you reload this hidden input field, just be sure to trigger a javascript parsing the String and updating your client-side Model. This can be done via the on* - events you can connect with Primefaces buttons.
Guys, can anybody help with the other parts?
One DropDownChoice list on my webapp takes very long time to create, because of getting options by some operations with LDAP connection and SQL connection. And because of that the whole page is loading much more than a couple of seconds - I'd say too much.
So what I want to achieve, is to use (best for me) the built-in Ajax functionality of Wicket to lazy load this dropdown, but I have some problems.
I know how to make regular DropDownChoice list, this simple example working great for me - link
I also know how to make lazy-loaded paragraph, from wicket-examples - link (Source Code -> LazyLoadingPage.html/LazyLoadingPage.java)
But putting it together throwing me exceptions and resulting Wicket's Internal error.
Here is how I try to do it:
in HTML:
<select wicket:id="lazy"></select>
in Java:
private String selected = "abc";
(...)
add(new AjaxLazyLoadPanel("lazy") {
#Override
public Component getLazyLoadComponent(String id) {
//simulating long time for simple list
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
return new DropDownChoice<String>(
id, new PropertyModel<String>(this,"selected"),
Arrays.asList("abc","def"));
}
});
}
And I'm getting Internal Error from Wicket, with that in logs:
ERROR Unexpected error occurred
Component [content] (path = [0:lazy:content]) must be applied to a tag of type [select], not: '<div wicket:id="content">' (line 0, column 0)
MarkupStream: [markup = jar:file:/C:/Program%20Files/Apache%20Software%20Foundation/Tomcat%207.0/webapps/devservices/WEB-INF/lib/wicket-extensions-1.5.7.jar!/org/apache/wicket/extensions/ajax/markup/html/AjaxLazyLoadPanel.html
, index = 0, current = ''
and stacktrace.
I would really appreciate some help, what I'm doing wrong, or maybe some better code examples.
Thanks to bert, I'm putting here full solution, in case someone will use it in the future.
We need to create our own panel, because AjaxLazyLoadPanel can only change one panel to another.
Example of MyPanel.html:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:panel>
<select wicket:id="project"></select>
</wicket:panel>
</body>
</html>
and MyPanel.java :
public class MyPanel extends Panel {
private String selected = <what you want>;
private List<String> projectList <what you want>;
public MyPanel(String id) {
super(id);
add(new DropDownChoice<String>(
"project", new PropertyModel<String>(this, "selected"), projectsList));
}
}
On your main page html simply add this:
<span wicket:id="lazy2"></span>
and in main page java file:
add(new AjaxLazyLoadPanel("lazy") {
#Override
public Component getLazyLoadComponent(String id) {
return new MyPanel(id);
}
});
Hope it will help someone else too :-)
as I asked time ago in this question, I solved my problem using this method:
In loging.xhtm, for instance:
<f:view locale="#{languageDetails.locale}" >
<head>
.....
<f:loadBundle basename="messages.Messages" var="msg1"/>
.....
</h:form>
</body>
</f:view>
2.In java source code I also made some changes:
public class LanguageDetails {
private static String locale = Locale.getDefault().getDisplayLanguage();
public void setLocale(String locale1) {
this.locale = locale1;
}
public synchronized String getLocale() {
return locale;
}
public synchronized String changeLanguage() {
return "changed";
}
}
But now I'm trying to have the same option, not just in Login page, but in other pages.
Adding the same code in other pages, doesn't work, because function setLocale is not called. Any help?
Thanks in advance
I realized, it's really important to put
<f:view locale="#{languageDetails.locale}" >
....
</f:view>
Or in every single file, or just in top file. Later, put <h:selectOneMenu> where necessary, but having always in mind that you can not have all <h:form> , <a4j:form>... etc. you want, it makes things more complicated. I put this form tags just on top files, and now everything is ok.
Hope this could help somebody.