I would like to implement a shopping cart with Spring, so I need to save an object Cart ( which has attributes like products, paymentType and deliveryType ) in session. I've tried to create it with bean and attribute "scope" set to "session", but it just doesn't work, should I use some additional annotations in my controller or Cart class? Any example usage would be really helpful :-) Thanks in advance.
#Component
#Scope("session")
public class Cart { .. }
and then
#Inject
private Cart cart;
should work, if it is declared in the web context (dispatcher-servlet.xml). An alternative option is to use the raw session and put your cart object there:
#RequestMapping(..)
public String someControllerMethod(HttpSession session) {
session.setAttribute(Constants.CART, new Cart());
...
Cart cart = (Cart) session.getAttribute(Constants.CART);
}
If you are injecting the shopping cart directly into your controller, the issue is likely happening because your controller is singleton scoped (by default), which is wider scope than the bean you're injecting. This excellent article gives an overview of four approaches to exactly what you're trying to do: http://richardchesterwood.blogspot.co.uk/2011/03/using-sessions-in-spring-mvc-including.html.
Here's a quick summary of solutions:
Scope the controller to session scope (use #scope("session") on controller level) and just have a shopping cart instance in the controller.
Scope the controller to request and have session-scoped shopping cart injected.
Just use the session directly - kind of messy, IMO.
Use Spring's annotation <aop:scoped-proxy/>.
All of the methods have their pros and cons. I usually go with option 2 or 4. Option 4 is actually pretty simple and is the only approach I have seen documented by Spring.
You just need to add Scope annotation as below with session and proxy mode
#Component
#Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class ShoppingCart implements Serializable{
}
Where ever you need to use shopping cart object, you can autowire it
#Service
public class ShoppingCartServiceImpl implements ShoppingCartService {
Logger logger = LoggerFactory.getLogger(ShoppingCartServiceImpl.class);
#Autowired
ShoppingCart shoppingCart;
}
Disclosure: I have developed a sample project, which uses spring MVC, angularJS and bootstrap that demonstrate Spring Session scope -
https://github.com/dpaani/springmvc-shoppingcart-sample
try to autowired HttpSession and spring will injects in a proxy to the HttpSession
#Autowired
private HttpSession httpSession;
Related
I'm hoping someone could shed some more light on my confusion with JPA entities in a Spring Boot project. I've heard that one should never call new in a Spring project. I understand that this is to allow Spring to manage all of the beans, and getting a bean can be done through injection or through the application context explicitly.
However, it's not clear to me how to get a new JPA Entity. If I have a class annotated with #Entity and a repository class that handles my data access, how do I obtain a new entity object in my service layer?
I've included #EntityScan in my application's main class so I would assume that Spring is aware of the entity. But when I try to get it through the ApplicationContext an exception is raised. This makes sense because I don't believe the #Entity annotated classes are Spring Beans, and I don't think it would be correct to also annotate it with #Component. Any clarification would be greatly appreciated.
I'm currently using the new keyword and creating the entity objects myself in the service layer. A very simple example is below:
entities/User.java
#Entity
#Table(name = "users")
public class User {
#Id
private Long id;
private String username;
// Getters & Setters ...
}
repositories/UserRepository.java
#Repository
public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}
services/UserServiceImpl.java
#Service
public class UserServiceImpl implements UserService {
UserRepository userRepository;
#Autowired
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void createAndSaveUser(String username) {
User user = new User();
user.setUsername(username);
userRepository.save(user);
}
}
And we could assume that there was some other controller classes that would utilize the service layer.
In this example I am explicitly calling the new keyword in the service class method createAndSaveUser. Is this the correct way to do it or should I be getting some prototype bean from Spring that maps to my JPA entity?
In spring you can autowire/inject your beans, components or services. However the entity should not be autowired since these interactions are done through your repository. Your repository can be autowired.
When you want to create a new instance of your entity you are allowed to call new, because this does not need to be managed by spring. You can simply use the autowired repository to save it in the database. This also works the other way around because obviously you would need the autowired repository to retrieve your entity.
So yes, your method is correct.
I hope this makes it clearer for you, if you have any questions feel free to ask :)
Whatever you are doing is completely valid in spring. In example you have provided above I could figure out that you want your entity class object itself to store the values. Its absolutely correct.
You have to use new keyword to achieve that.
If you still wish to not create a new object for your Entity you have another option to do it through Bean/POJO/VO classes and mapping your entity object with these classes.
But Still i will tell that whatever you have done is completely fine.
Actually the object you are creating is for storing value purpose not just because you have some method is there in your class and so you are bound to create new Object to be able to call that method(As we do in normal java project).In spring that is handle by #Autowired annotation to create object.
Simple example is you will be auto-wiring your repositories in your service classes.
I hope this help.
It sounds good to me: you create your entity and then ask the repository to store it.. no problem with Spring.
have you checked this out? :
http://spring.io/guides/gs/accessing-data-jpa/
have fun
I'm trying to get used to how JSF works with regards to accessing data (coming from a spring background)
I'm creating a simple example that maintains a list of users, I have something like
<h:dataTable value="#{userListController.userList}" var="u">
<h:column>#{u.userId}</h:column>
<h:column>#{u.userName}</h:column>
</h:dataTable>
Then the "controller" has something like
#Named(value = "userListController")
#SessionScoped
public class UserListController {
#EJB
private UserListService userListService;
private List<User> userList;
public List<User> getUserList() {
userList = userListService.getUsers();
return userList;
}
}
And the "service" (although it seems more like a DAO) has
public class UserListService {
#PersistenceContext
private EntityManager em;
public List<User> getUsers() {
Query query = em.createQuery("SELECT u from User as u");
return query.getResultList();
}
}
Is this the correct way of doing things? Is my terminology right? The "service" feels more like a DAO? And the controller feels like it's doing some of the job of the service.
Is this the correct way of doing things?
Apart from performing business logic the inefficient way in a managed bean getter method, and using a too broad managed bean scope, it looks okay. If you move the service call from the getter method to a #PostConstruct method and use either #RequestScoped or #ViewScoped instead of #SessionScoped, it will look better.
See also:
Why JSF calls getters multiple times
How to choose the right bean scope?
Is my terminology right?
It's okay. As long as you're consistent with it and the code is readable in a sensible way. Only your way of naming classes and variables is somewhat awkward (illogical and/or duplication). For instance, I personally would use users instead of userList, and use var="user" instead of var="u", and use id and name instead of userId and userName. Also, a "UserListService" sounds like it can only deal with lists of users instead of users in general. I'd rather use "UserService" so you can also use it for creating, updating and deleting users.
See also:
JSF managed bean naming conventions
The "service" feels more like a DAO?
It isn't exactly a DAO. Basically, JPA is the real DAO here. Previously, when JPA didn't exist, everyone homegrew DAO interfaces so that the service methods can keep using them even when the underlying implementation ("plain old" JDBC, or "good old" Hibernate, etc) changes. The real task of a service method is transparently managing transactions. This isn't the responsibility of the DAO.
See also:
I found JPA, or alike, don't encourage DAO pattern
DAO and JDBC relation?
When is it necessary or convenient to use Spring or EJB3 or all of them together?
And the controller feels like it's doing some of the job of the service.
I can imagine that it does that in this relatively simple setup. However, the controller is in fact part of the frontend not the backend. The service is part of the backend which should be designed in such way that it's reusable across all different frontends, such as JSF, JAX-RS, "plain" JSP+Servlet, even Swing, etc. Moreover, the frontend-specific controller (also called "backing bean" or "presenter") allows you to deal in a frontend-specific way with success and/or exceptional outcomes, such as in JSF's case displaying a faces message in case of an exception thrown from a service.
See also:
JSF Service Layer
What components are MVC in JSF MVC framework?
All in all, the correct approach would be like below:
<h:dataTable value="#{userBacking.users}" var="user">
<h:column>#{user.id}</h:column>
<h:column>#{user.name}</h:column>
</h:dataTable>
#Named
#RequestScoped // Use #ViewScoped once you bring in ajax (e.g. CRUD)
public class UserBacking {
private List<User> users;
#EJB
private UserService userService;
#PostConstruct
public void init() {
users = userService.listAll();
}
public List<User> getUsers() {
return users;
}
}
#Stateless
public class UserService {
#PersistenceContext
private EntityManager em;
public List<User> listAll() {
return em.createQuery("SELECT u FROM User u", User.class).getResultList();
}
}
You can find here a real world kickoff project here utilizing the canonical Java EE / JSF / CDI / EJB / JPA practices: Java EE kickoff app.
See also:
Creating master-detail pages for entities, how to link them and which bean scope to choose
Passing a JSF2 managed pojo bean into EJB or putting what is required into a transfer object
Filter do not initialize EntityManager
javax.persistence.TransactionRequiredException in small facelet application
It is a DAO, well actually a repository but don't worry about that difference too much, as it is accessing the database using the persistence context.
You should create a Service class, that wraps that method and is where the transactions are invoked.
Sometimes the service classes feel unnecessary, but when you have a service method that calls many DAO methods, their use is more warranted.
I normally end up just creating the service, even if it does feel unnecessary, to ensure the patterns stay the same and the DAO is never injected directly.
This adds an extra layer of abstraction making future refactoring more flexible.
I am trying to figure out a solution for a small problem I have encountered whilst developing a small application. I am trying to pass an object created within one backing-bean and then later using that same object I created within another backing-bean. However, I would not like to make these backing-beans #SessionScoped, and preferably not use the #ManagedBean as I am using CDIfor my JavaEE application.
Is there anyway I could do this using CDI annotations and injecting one backing-bean to another and then have the ability to access that object previously created?
As an example, refer to the below beans:
#Named
#ViewScoped
public RegisterController implements Serializable {
User user = new User();
// Getter and Setter methods which are populated by the JSF page
}
Get Object User created within the above bean and use it within the controller below:
#Named
#ViewScoped
public PaymentController implements Serializable {
#Inject RegisterController registerController; // Injecting bean
registerController.getUser().getName(); //this is null when I try access the properties of the object 'User'. I am assuming this is because #ViewScoped annotated on the 'RegisterController' class?
// I would like to use the User object created in 'RegisterController' here an access properties etc...
}
Could I use the #Inject annotation offered by the CDI?
UPDATE
Ok, so I have got the above working when I annotate the RegisterController with the SessionScoped annotation, however I do not want this Bean annotated SessionScoped as I will probably run into further implications down the track, such as pre-population of fields, etc... Any ideas how to implement this any other way?
Well, #ViewScoped is too short to the purpose and #SessionScoped is too long. Then why not use #ConversationScoped?
See here.
you can use in RegistrationController:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("user", user);
and in PaymentController:
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get("user");
this is very useful, you can save the objects you want in the map.
Using: EJB 3.1, JBoss AS 7, RestEasy.
I have a session scoped bean which I want to user to store user informations for the session.
import java.io.Serializable;
import javax.enterprise.context.SessionScoped
#SessionScoped
public class LoggedInUser implements Serializable {
private String id;
...
}
If the user open my web application a filter extract header informations (application runs behind a webseal) which contains a user identification. I need to create a logged in user object (see LoggedInUser above) there (after calling ldap). Afterwards I want to inject this LoggedInUser object in different #Stateless Beans, but LoggedInUser is always "empty" (members are null).
Inject sample:
#Path("/country")
#Stateless
public class CountryController extends AbstractController {
#Inject
private Logger LOGGER;
#Inject
private LoggedInUser loggedInUser;
//#Inject dont work too..
//private Instance<LoggedInUser> loggedInstance
What do Im wrong?
Judging by the comment and the question - you need some help with EJB concepts.
#SessionScoped beans are beans that have one instance per session. Every #Inject with bean like that during one session will reference the same object. That's it however - if you want your bean to contain some information specific to that session, you will need to put it there yourself, using setters or other methods like you would do in every normal Java class.
I recently installed the XRebel plugin, which allows you to see current session size.
I discovered, that the session instantly gets to 10 mb on first page load(initialization of the auth session bean.).
To my setup:
I am using JSF 2.2, Spring 4 and Hibernate 4.
DAO Layer > Service Layer > Managed Bean
DAO Layer
#Named
#Singleton
#Repository
public class UserDao extends BaseDao<User>
{
...
}
Service Layer
#Service
#Named
#Singleton
public class UserService extends BaseService<User>
{
#Autowired
private UserDao dao;
...
}
My auth session bean, that gets loaded on first page load
#Named
#Component
#Scope("session")
public class Auth implements Serializable
{
#Autowired
private UserService userService;
...
}
In my applicationContext.xml I am using
<context:component-scan base-package="com.mypackage" />
This is a general issue I have when I autowire service beans in my session beans.
The Userservice only contains methods to retreive, save and delete user objects, there is no ArrayList containing users or anything else.
I have two #Autowired Services in my auth bean - UserService and SessionService.
If I commment out UserService, SessionService will reach the same size. If I comment out both there is a "DestructionCallbackBindingListener" from "org.springframework.web.context.request.ServletRequestAttribute..." that reaches 8mb instantly.
What am I doing wrong? How do I decrease the session size ?
I gladly accept any help.
Here is an image of XRebel showing that the userService takes about 8mb size in session. http://i.stack.imgur.com/TBXx3.png
Looking at XRebel, it seems that the beanFactory is saved in the user session.
I posted in the official forums regarding XRebel. This is the answer I received.
Indeed, the beanFactory is reachable from the session, through the
CGLIB proxy. We may need to improve to how we recognize objects that
are shared or should not be considered part of the session.
We try to show how much memory each session takes, but Spring
beanFactories are of course shared between sessions usually.
Often the fact that we filter out transient fields from the session
is enough, but we’ll take a look at the CGLIB/Spring proxies to see
how we can filter them out by a general rule or maybe we can just add
specific Spring classes to an ignore list.
In short: The beanfactory can be Ignored when looking at session size, optionally, if possible mark the autowired services transient.
Indeed you can ignore it mentally for now or if it’s possible then
yes, making the variables transient would exclude them.