I am reading about HttpSessionAttributeListener and here is a small example i made.
I have one doubt though. The code is given below
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
doPost(request,response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
HttpSession session = request.getSession();
Dog d = new Dog();
d.setName("Peter");
session.setAttribute("test", d);
/*Dog d1 = new Dog();
d1.setName("Adam");
*/
d.setName("Adam");
session.setAttribute("test",d);
}
}
Here is my Listener class
public class MyAttributeListener implements HttpSessionAttributeListener {
#Override
public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
System.out.println("Attribute Added");
String attributeName = httpSessionBindingEvent.getName();
Dog attributeValue = (Dog) httpSessionBindingEvent.getValue();
System.out.println("Attribute Added:" + attributeName + ":" + attributeValue.getName());
}
#Override
public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
String attributeName = httpSessionBindingEvent.getName();
String attributeValue = (String) httpSessionBindingEvent.getValue();
System.out.println("Attribute removed:" + attributeName + ":" + attributeValue);
}
#Override
public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
String attributeName = httpSessionBindingEvent.getName();
Dog attributeValue = (Dog) httpSessionBindingEvent.getValue();
System.out.println("Attribute replaced:" + attributeName + ":" + attributeValue.getName());
}
}
Here is my model
public class Dog {
private String name ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The confusion is when i run this program, the listener calls the attribute added and
replaced perfectly. When i uncomment the code in my servlet and comment
d.setName("Adam")
The attribute replaced does get called. But the value of name remains Peter only. Why
is that? What's the reason? Another question when do we use HttpSessionAttributeListener
and HttpSessionListener in particular. Any practical usages?
Thanks,
Peter
Because the javadoc says:
Returns the value of the attribute that has been added, removed or
replaced. If the attribute was added (or bound), this is the value of
the attribute. If the attribute was removed (or unbound), this is the
value of the removed attribute. If the attribute was replaced, this is
the old value of the attribute.
In the first case, the old value and the new value are the same, so you see the new dog name.
HttpSessionListener is used to be aware of session creation and destruction. HttpSessionAttributeListener is used to be aware of new, removed and replaced attributes in the session. They're very different.
Related
Hello I am Trying to pass Variable data from database from one Controller to another, but I Have one problem, when I am passing the data to the controller A to Controller B, appear a Null value, the jerarchy between Scenes is this:
LoginController->AdminController->UserController
in the LoginController to Access AdminController and Pass the Value i do this:
public String getRoladmin() {
return roladmin;
}
public void setRoladmin(String roladmin) {
this.roladmin = roladmin;
}
public String roladmin="";
I Capture the Variable roladmin in this portion of my code like this:
while(rs.next()) {
comparauser=rs.getString("NOMBREUSUARIO");
comparapass=rs.getString("PASS");
miadmin=rs.getString("NOMBRE_ADMIN");
roladmin=rs.getString("ROL_ADMIN");
}
to access the Stage I validate if the user and pass are correct like this:
----rest of code--- if(comparauser.equals(fusuario.getText().toString())&&comparapass.equals(fcontrasena.getText().toString().trim())) {
try {
Stage administrador=new Stage();
FXMLLoader carga = new FXMLLoader(getClass().getResource("Admin.fxml"));
Parent StackPane = (Parent)carga.load();
Scene scene = new Scene(StackPane);
AdminScreenController loadl = carga.<AdminScreenController>getController();
/*loadl.UserScreen.setText("Bienvenido"+" "+fusuario.getText().toString());*/
loadl.UserScreen.setText("Bienvenido"+" "+miadmin);
/* String r=loadl.UserScreen.getText().toString();*/
-----in this part I call the LoginController and pass the variable Roladmin------
----begin of call--
String h=LoginController.this.roladmin;
LoginController.this.setRoladmin(h);
String r=LoginController.this.getRoladmin();
loadl.setCapdata(r);
-----end of call-----
if(!r.equals("ADMINISTRADOR")) {
loadl.btnimg5.setDisable(true);
loadl.btnimg5.setStyle("-fx-opacity:0.65;");
}
else {
loadl.btnimg5.setDisable(false);
}
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
administrador.setScene(scene);
administrador.setTitle("AdminScreen");
Stage login=(Stage)fusuario.getScene().getWindow();
login.hide();
administrador.show();
}catch(Exception e) {
Logger.getLogger(Application.class.getName()).log(Level.SEVERE, null, e);
}
}
---rest of code---
now i Pass that variable to the AdminController like this
in AdminController i have this:
public String capdata;
public String h;
public String getCapdata() {
return capdata;
}
public String setCapdata(String data) {
return this.capdata = data;
}
this is the code i have to load UserController Stage:
public void UserView() throws IOException {
Stage userstage = new Stage();
FXMLLoader cargauser =new FXMLLoader(getClass().getResource("UsuarioScreen.fxml"));
Parent StackPane = (Parent)cargauser.load();
UserController cargatodouser = cargauser.<UserController>getController();
String pasadato=UserScreen.getText().toString();
cargatodouser.iduser.setText(pasadato);
---begin of call to pass the variable---
h=AdminScreenController.this.getCapdata();
---end of call---
/*String r=cargatodouser.iduser.getText().toString();*/
Scene scene = new Scene(StackPane);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
userstage.setScene(scene);
userstage.setTitle("QuoraApp");
Stage AdminScreen=(Stage)btnimg1.getScene().getWindow();
AdminScreen.hide();
userstage.show();
}
now when i am passing the variable to the UserController Class i have a null value I am doing this:
In UserController class i have this to go back AdminController:
public String capturau;
public String getCapturau() {
return capturau;
}
public String setCapturau(String capturau) {
return this.capturau = capturau;
}
public void inicio() throws IOException {
Stage administrador=new Stage();
FXMLLoader carga = new FXMLLoader(getClass().getResource("Admin.fxml"));
Parent StackPane =(Parent) carga.load();
AdminScreenController loadl = carga.<AdminScreenController>getController();
String pasadato=iduser.getText().toString();
loadl.UserScreen.setText(pasadato);
/*Captura.setText(loadl.getCapdata());
String captura=Captura.getText().toString();
System.out.println(captura);*/
UserController.this.setCapturau(loadl.getCapdata());
String gg=UserController.this.getCapturau();
System.out.println(gg);
}
what i am doing wrong? a little help here please.
You need to look into the concept of static variables
Here is a static variable I declare on one Controller and use and another Controller
A BIG word of caution about using static variables or Global Variables
What ever you put in a static variable it holds that value till you clear it or change it
static Integer strID;
Here is the use of the static variable strID in the other Controller Class
Notice it needs to be imported to the new Controller
import static diary.ChildTableViewController.strID;
private void ReadDetailView() throws SQLException{
stmnt = conn.createStatement();
///String sql = "SELECT * FROM Child WHERE CID = "+strID;
///ResultSet rs = stmnt.executeQuery(sql);
ResultSet rs = stmnt.executeQuery("SELECT * FROM Child WHERE CID = "+strID);
Welcome to SO
I am trying to lazily fetch PetDetails entity using JPA. However, I get LazyInitialization Exception. I read many solutions for this exception and came to find solution using JOIN FETCH in JPQL. Also people recommended using Criteria queries. However, I am trying to look for a solution if there is a way I can fetch the PetDetails entity the way I want without using queries directly or depending on Criteria API or without using EAGER FETCH. I might be missing something. I would appreciate for any help or suggestion. Below are the code samples:
1. Controller class:
#Controller
public class PetController {
private static Logger LOGGER = Logger.getLogger(PetController.class);
#Autowired
private PetService petService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public void manageAndDisplayPet() {
PetDetails petDetails = new PetDetails();
petDetails.setName("DOG");
Pet pet = new Pet(petDetails);
// save
petService.savePet(pet);
// retrieve
LOGGER.debug("**********************" + petService.getPet());
LOGGER.debug("**********************" + pet.getPetDetails());
}
}
2. PetService class:
#Service
public class PetService {
#Autowired
private PetDAO petDAO;
#Transactional
public void savePet(Pet pet) {
petDAO.savePet(pet);
}
#Transactional
public Pet getPet() {
return petDAO.getPet();
}
}
3. PetDAO class
#Repository
#EnableTransactionManagement
public class PetDAO {
#PersistenceContext(unitName = "petcontext")
private EntityManager entityManagerFactory;
public void savePet(Pet pet) {
entityManagerFactory.persist(pet);
}
public Pet getPet() {
Pet pet = (Pet) entityManagerFactory.find(Pet.class, 1);
return pet;
}
}
4. Pet Entity:
#Entity
#Table(name = "t_pet")
public class Pet {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinColumn(name = "pet_details")
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private PetDetails petDetails;
public Pet() {
}
public Pet(PetDetails petDetails) {
this.petDetails = petDetails;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public PetDetails getPetDetails() {
return petDetails;
}
public void setPetDetails(PetDetails petDetails) {
this.petDetails = petDetails;
}
#Override
public String toString() {
return "Pet [id=" + id + ", petDetails=" + petDetails + "]";
}
}
5. PetDetails Entity:
#Entity
#Table(name = "pet_details")
public class PetDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "pet_name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "PetDetails [id=" + id + ", name=" + name + "]";
}
}
Thank you for your help.
Easy thing you can do is to call pet.getPetDetails() inside PetService#getPet. This solution is not very clear, but it will force JPA to fetch entity too. This is solution for your question, but not the good way anyways.
What is the good way?
The good way may depend on your particular usecase:
If you need this details everytime — you should use EAGER_FETCH
If you need it time to time than good solution it to use JPQL with JOIN FETCH
But the best way is to select not entites, but DTOs, which will contain whole information which your application needs and not more. It may be achieved with SELECT NEW expression as described here
I have this simple form with 2 checkboxes and a submit button. When I submit the form, I get this error
HTTP Status 400 The request sent by the client was syntactically incorrect.
This is my POJO:
public class Menu{
private String day;
private String name;
private int price;
public Menu(){
}
public Menu(String day, String name, int price) {
this.day = day;
this.name = name;
this.price = price;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDay() {
return day;
}
public void setDay(String l) {
this.day = l;
}
#Override
public int hashCode() {
int hash = 3;
hash = 7 * hash + this.day.hashCode();
hash = 7 * hash + this.name.hashCode();
return hash;
}
#Override
public boolean equals(Object object) {
boolean result = false;
System.out.println("ARE YOU EVER CALLLED HOW MANY TIMES");
if (object == null || object.getClass() != getClass()) {
result = false;
} else {
Menu sc = (Menu) object;
if (this.day == sc.getDay() && this.name == sc.getName()
&& this.price == sc.getPrice()) {
result = true;
}
}
return result;
}
This is my Order class:
public class Order {
private List<Menu> menus = new ArrayList<Menu>();
public Order(){}
public Order(ArrayList<Menu> menus){
this.menus = menus;
}
public List<Menu> getMenus() {
return menus;
}
public void setMenus(ArrayList<Menu> menus) {
this.menus = menus;
}
}
And this is my controller:
#Controller
public class RestaurantController {
#RequestMapping(value = "/menu", method = RequestMethod.GET)
public String menuPage(Model model){
Order o = new Order();
ArrayList<Menu> m = new ArrayList<Menu>();
m.add(new Menu("Sunday", "Phir Aloo", 12));
m.add(new Menu("Sunday", "Phir Cholay", 9));
model.addAttribute("today", m);
model.addAttribute("order", o);
return "/menu";
}
#RequestMapping(value = "/confirm", method = RequestMethod.POST)
public String done(#ModelAttribute(value="order") Order order, Model model){
return "/confirm";
}
And this is my menu.jsp: (http://localhost:9080/res/menu)
<form:form modelAttribute="order" method="post" action="/res/confirm">
<c:forEach items="${today}" var="r">
<form:checkbox path="menus" value="${r}" label="${r.name } ${r.price }" />
</c:forEach>
<input type="submit" value="Submit Data">
</form:form>
Now I just expect Class Order's property 'menus' to be filled with selected checkboxes. Instead I get this error "The request sent by the client was syntactically incorrect. I have looked up every possible answer on this website but nothing seems to be solving the problem.
After #R Sawant's suggestion I was able to solve the problem. Here is my Property Editor.
public class MenuTypeEditor extends PropertyEditorSupport {
public void setAsText(String text) {
setValue(new Menu(text.toUpperCase()));
}
}
I kept this class inside the same package which has Menu.java and Order.java
Now inside my controller wrote this:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Menu.class, new MenuTypeEditor());
}
And voila! Magic happened.
I hope this answer can help someone.
The problem is with the value you are posting when the check box is ticked. Look at the below code
<form:checkbox path="menus" **value="${r}"** label="${r.name } ${r.price }" />
See what have assigned to value attribute in the above line. Its whole object of menu. It will essentially post the toString() representation of the object. Since you have not implemented toString() for Menu class, something like Menu#1ed2e55e gets posted for the check box value. Spring is unable to convert this to something meaningful and hence the problem.
You have to make use of property editor support to deal with these type of situations. Property editor will help you convert string to Object and vice versa. In your case String to Menu object and vice versa. Take a look at examples of property editors. Hope this helps
Edit:- a google search got this result. Take a look at it, may help you to understand.
I would like to write something like :
#Autowired
private SpringTemplateEngine engine;
....
// Thymeleaf Context
WebContext thymeleafContext = new WebContext(request, response, request.getServletContext(), locale);
// cached html of a thymeleaf template file
String cachedHtml=....
// process the cached html
String html=engine.process(cachedHtml, thymeleafContext);
By default, the [process] method can't do that. I can understand from the docs that I need a special Template Resolver :
In order to execute templates, the process(String, IContext) method will be used:
final String result = templateEngine.process("mytemplate", ctx);
The "mytemplate" String argument is the template name, and it will relate to the physical/logical location of the template itself in a way configured at the template resolver/s.
Does anyone know how to solve my problem ?
The goal is to cache the Thymeleaf templates (files) in strings and then process theses strings rather than the files.
The solution we ended up using consisted of a new IResourceResolver with a custom Context rather than a custom TemplateResolver. We chose this because we still wanted to use classpath scanning in most cases, but occasionally had dynamic content.
The following shows how we did it:
public class StringAndClassLoaderResourceResolver implements IResourceResolver {
public StringAndClassLoaderResourceResolver() {
super();
}
public String getName() {
return getClass().getName().toUpperCase();
}
public InputStream getResourceAsStream(final TemplateProcessingParameters params, final String resourceName) {
Validate.notNull(resourceName, "Resource name cannot be null");
if( StringContext.class.isAssignableFrom( params.getContext().getClass() ) ){
String content = ((StringContext)params.getContext()).getContent();
return IOUtils.toInputStream(content);
}
return ClassLoaderUtils.getClassLoader(ClassLoaderResourceResolver.class).getResourceAsStream(resourceName);
}
public static class StringContext extends Context{
private final String content;
public StringContext(String content) {
this.content = content;
}
public StringContext(String content, Locale locale) {
super(locale);
this.content = content;
}
public StringContext(String content, Locale locale, Map<String, ?> variables) {
super(locale, variables);
this.content = content;
}
public String getContent() {
return content;
}
}
Test Case
public class StringAndClassLoaderResourceResolverTest {
private static SpringTemplateEngine templateEngine;
#BeforeClass
public static void setup(){
TemplateResolver resolver = new TemplateResolver();
resolver.setResourceResolver(new StringAndClassLoaderResourceResolver());
resolver.setPrefix("mail/"); // src/test/resources/mail
resolver.setSuffix(".html");
resolver.setTemplateMode("LEGACYHTML5");
resolver.setCharacterEncoding(CharEncoding.UTF_8);
resolver.setOrder(1);
templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(resolver);
}
#Test
public void testStringResolution() {
String expected = "<div>dave</div>";
String input = "<div th:text=\"${userName}\">Some Username Here!</div>";
IContext context = new StringAndClassLoaderResourceResolver.StringContext(input);
context.getVariables().put("userName", "dave");
String actual = templateEngine.process("redundant", context);
assertEquals(expected, actual);
}
#Test
public void testClasspathResolution(){
IContext context = new Context();
context.getVariables().put("message", "Hello Thymeleaf!");
String actual = templateEngine.process("dummy", context);
String expected = "<h1>Hello Thymeleaf!</h1>";
assertEquals(expected, actual);
}
}
Dummy template file at src/main/resources/mail/dummy.html
<h1 th:text="${message}">A message will go here!</h1>
Note: We used Apache CommonsIO's IOUtils for converting the String to an InputStream
You can implement your own TemplateResolver and IResourceResolver to work with String.
for simple unit tests:
static class TestResourceResolver implements IResourceResolver {
public String content = "";
#Override
public String getName() {
return "TestTemplateResolver";
}
#Override
public InputStream getResourceAsStream(TemplateProcessingParameters templateProcessingParameters,
String resourceName) {
return new ByteArrayInputStream(content.getBytes());
}
}
or just use org.thymeleaf.templateresolver.StringTemplateResolver in Thymeleaf 3
Yep StringTemplateResolver is the way to go.
public class ReportTemplateEngine {
private static TemplateEngine instance;
private ReportTemplateEngine() {}
public static TemplateEngine getInstance() {
if(instance == null){
synchronized (ReportTemplateEngine.class) {
if(instance == null) {
instance = new TemplateEngine();
StringTemplateResolver templateResolver = new StringTemplateResolver();
templateResolver.setTemplateMode(TemplateMode.HTML);
instance.setTemplateResolver(templateResolver);
}
}
}
return instance;
}
}
I have an Apache Wicket page that has a DataTable with a column that needs to show the statuses, Red, Yellow, Green. If the content of the column is Red, I want to change the CSS class to red-status, if yellow yellow-status, else green-status. I can't seem to get at the data in the way you can from a clickable property column. How do you get at the data in a PropertyColumn, or is there another way to do this in a DataTable? Thank you!
UPDATE
Thank you, Martin. Here's what I came up with:
#Override
public void populateItem(Item<ICellPopulator<T>> cellItem, String componentId, final IModel<T> rowModel) {
Label label = new Label(componentId, getDataModel(rowModel));
cellItem.add(label);
LOGGER.debug("populateItem: label DefaultModelObject: {}", (String) label.getDefaultModelObject());
label.add(new AttributeModifier("class", new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
ProcessingTime processingTime = (ProcessingTime) rowModel.getObject();
#Override
public String getObject() {
String cssClass = null;
if (StringUtils.equals("Red", processingTime.getStatus())) {
cssClass = "red-status";
} else if (StringUtils.equals("Yellow", processingTime.getStatus())) {
cssClass = "yellow-status";
} else if (StringUtils.equals("Green", processingTime.getStatus())) {
cssClass = "green-status";
} else {
cssClass = "process-status";
}
return cssClass;
}
}));
}
First thing first, look at the populateItem of PropertyColumn, how does the implementation looks like, in Wicket 6 (similar like other versions) it is:
public class PropertyColumn<T, S> extends AbstractColumn<T, S> implements IExportableColumn<T, S, Object>
...
#Override
public void populateItem(final Item<ICellPopulator<T>> item, final String componentId,
final IModel<T> rowModel)
{
item.add(new Label(componentId, createLabelModel(rowModel)));
}
...
}
You have to modify the inner component that is create as the label of the column.
First method: create your own component (also your component is able to contain its own mechanism of creation css class or style instead of adding an AttributeModifier here):
#Override
public void populateItem(final Item<ICellPopulator<T>> item, final String componentId,
final IModel<T> rowModel)
{
super.populateItem(item, componentId, rowModel);
MarkupContainer c = item.get(componentId);
c.add(new AttributeModifier("class", new AbstractReadonlyModel<String>() {
private static final long serialVersionUID = 1L;
#Override
public String getObject() {
// some logic how to which css you want to apply
return "MY-CSS-CLASS";
}
}));
}
or you can let Wicket to create the Label component itself and you just add an AttributeModifier:
#Override
public void populateItem(final Item<ICellPopulator<T>> item, final String componentId, final IModel<T> rowModel)
{
super.populateItem(item, componentId, rowModel);
Label l = new Label(componentId, createLabelModel(rowModel));
item.add(l);
l.add(new AttributeModifier("class", new AbstractReadonlyModel<String>() {
private static final long serialVersionUID = 1L;
#Override
public String getObject() {
// some logic how to which css you want to apply
return "MY-CSS-CLASS";
}
}));
}
NOTE: the method 'createLabelModel' is deprecated in Wicket 6, rather to use 'getDataModel' instead.