-Xmx2048m -Xms512m -XX:MaxPermSize=768m -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
====== Package structure : ======
''be.mentoringsystems.applicationname.dao''
Contains DAO interfaces, naming ObjectnameDAO
''be.mentoringsystems.applicationname.dao.hibernate''
Contains DAO implementations, naming HibernateObjectnameDAO, extends HibernateDaoSupport, implements ObjectnameDAO
''be.mentoringsystems.applicationname.model.db''
Contains models which will be stored in the database, naming Ojectname
''be.mentoringsystems.applicationname.presentation''
Contains controllers which will be accessed via Rest, naming ObjectnameController
''be.mentoringsystems.applicationname.security''
Contains overrides for security
''be.mentoringsystems.applicationname.service''
Contains Service interfaces, naming ObjectnameService
''be.mentoringsystems.applicationname.service.impl''
Contains Service implementations, naming ObjectnameServiceImpl, implements ObjectnameService, uses ObjectnameDAO & Transactional annotations
===== German Projects =====
''de.jcpis.applicationname''
see above for details.
====== How to start : ======
Start with creating mocks & database model
Create a new project : ''New Project -> Maven -> Web Application''
===== POM : =====
Change the POM (configuration files -> ''pom.xml'') to this :
com.msfcore
MentoringSystems
1.2
4.0.0
be.mentoringsystems.applicationname
applicationname
war
A description of the application
1.0-SNAPSHOT
applicationname
http://maven.apache.org
javax.servlet
servlet-api
2.5
provided
javax.servlet.jsp
jsp-api
2.1
provided
org.springframework
spring-aop
3.0.5.RELEASE
org.springframework
spring-asm
3.0.5.RELEASE
org.springframework
spring-aspects
3.0.5.RELEASE
org.springframework
spring-beans
3.0.5.RELEASE
org.springframework
spring-context
3.0.5.RELEASE
org.springframework
spring-context-support
3.0.5.RELEASE
org.springframework
spring-core
3.0.5.RELEASE
commons-logging
commons-logging
org.springframework
spring-expression
3.0.5.RELEASE
org.springframework
spring-orm
3.0.5.RELEASE
org.springframework
spring-oxm
3.0.5.RELEASE
org.springframework
spring-tx
3.0.5.RELEASE
org.springframework
spring-web
3.0.5.RELEASE
org.springframework
spring-webmvc
3.0.5.RELEASE
org.springframework.security
spring-security-acl
3.0.5.RELEASE
org.springframework.security
spring-security-aspects
3.0.5.RELEASE
org.springframework.security
spring-security-config
3.0.5.RELEASE
org.springframework.security
spring-security-core
3.0.5.RELEASE
org.springframework.security
spring-security-taglibs
3.0.5.RELEASE
org.springframework.security
spring-security-web
3.0.5.RELEASE
org.codehaus.jackson
jackson-core-lgpl
1.6.9
org.codehaus.jackson
jackson-mapper-lgpl
1.6.9
javax.transaction
jta
1.1
mysql
mysql-connector-java
5.1.32
asm
asm
3.3.1
asm
asm-attrs
1.5.3
cglib
cglib
2.2
org.hibernate
jtidy
r8-21122004
javax.activation
activation
1.1.1
javax.annotation
jsr250-api
1.0
javassist
javassist
3.12.0.GA
antlr
antlr
2.7.6
org.hibernate
hibernate-ehcache
3.6.10.Final
org.hibernate
hibernate-entitymanager
3.6.10.Final
org.hibernate
hibernate-tools
3.2.3.GA
org.hibernate
hibernate-commons-annotations
3.2.0.Final
org.slf4j
slf4j-api
org.hibernate
hibernate-core
3.6.10.Final
org.slf4j
slf4j-api
commons-fileupload
commons-fileupload
1.2.2
commons-codec
commons-codec
1.8
commons-logging
commons-logging
1.1.3
commons-pool
commons-pool
1.5.5
commons-beanutils
commons-beanutils
1.8.3
commons-logging
commons-logging
commons-beanutils
commons-beanutils-bean-collections
1.8.3
commons-logging
commons-logging
commons-beanutils
commons-beanutils-core
1.8.3
commons-logging
commons-logging
commons-collections
commons-collections
3.1
commons-dbcp
commons-dbcp
1.4
commons-io
commons-io
2.0
commons-lang
commons-lang
2.6
dom4j
dom4j
1.6.1
log4j
log4j
1.2.16
org.slf4j
slf4j-api
1.6.1
org.slf4j
slf4j-log4j12
1.6.1
net.bull.javamelody
javamelody-core
1.52.0
org.apache.tomcat.maven
tomcat6-maven-plugin
2.2
both
org.apache.maven.plugins
maven-dependency-plugin
2.8
org.apache.maven.plugins
maven-resources-plugin
2.7
${project.build.sourceEncoding}
org.apache.maven.plugins
maven-surefire-plugin
2.15
${skipTests}
-XX:-UseSplitVerifier
This will set most of your dependencies straight, \\
the parent pom ensures all projects use UTF-8 encoding for files & sets some maven plugins.
===== web.xml : =====
Now we need the following in our ''WEB-INF/web.xml'' \\
Remove Spring Security if you are not using it!
contextConfigLocation
classpath:net/bull/javamelody/monitoring-spring.xml
/WEB-INF/applicationname.xml
net.bull.javamelody.SessionListener
org.springframework.web.context.ContextLoaderListener
org.springframework.web.util.Log4jConfigListener
applicationname
org.springframework.web.servlet.DispatcherServlet
2
applicationname
/
encodingFilter
org.springframework.web.filter.CharacterEncodingFilter
encoding
UTF-8
forceEncoding
true
encodingFilter
/
encodingFilter
/*
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
monitoring
net.bull.javamelody.MonitoringFilter
url-exclude-pattern
/static/.*
monitoring
/*
240
index.htm
json
application/json
===== applicationname.xml : =====
applicationname.xml is a spring context file which will bind most of the configuration files together \\
Here is a basic file for ''/WEB-INF/applicationname.xml''
seperate config files (services, security & database) now go into ''/WEB-INF/classes'', \\
you get them there by creating the following folder : ''/src/main/resources'' which in netbeans will translate to ''Other Sources/src/main/resources/''
Now that we have a skeleton, it's time to add some classes
====== Class buildup ======
===== Model =====
Let's start with a model
package be.mentoringsystems.applicationname.model.db;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.Type;
// JPA: mark it as a database entity
@Entity
// JPA: which table
@Table(name = "Login")
// JSON: hide properties (hibernate properties have difficulty serializing, these properties were added automatically by hibernate byte code manipulation)
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "password"})
public class Login implements Serializable {
private Integer id;
private String login;
private String password;
private boolean admin = false;
private boolean active = true;
private String firstname;
private String lastname;
private String email;
private Date createdOn = new Date();
private Date lastModified = new Date();
// JPA: marks date fields
@Temporal(TemporalType.TIMESTAMP)
// JPA: column definition, non-nullable fields require mentioning
@Column(name = "createdOn", nullable = false, length = 19)
// you can add serializers to always return the date formatted like dd.MM.yyyy
//@JsonSerialize(using = DateTimeFormatter.class)
public Date getCreatedOn() {
return this.createdOn;
}
public void setCreatedOn(final Date createdOn) {
this.createdOn = createdOn;
}
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "lastModified", length = 19)
//@JsonSerialize(using = DateTimeFormatter.class)
public Date getLastModified() {
return this.lastModified;
}
public void setLastModified(final Date lastModified) {
this.lastModified = lastModified;
}
/*@Column(name="rabat")
public String getRabat() {
return rabat;
}
public void setRabat(String rabat) {
this.rabat = rabat;
}*/
/*public LoginAttribut getLoginAttribut(final String key) {
for(LoginAttribut attribut : this.getLoginAttributs()) {
if(attribut.getParamKey().equals(key)) {
return attribut;
}
}
final LoginAttribut loginAttribut = new LoginAttribut();
loginAttribut.setParamKey(key);
loginAttribut.setLogin(this);
this.getLoginAttributs().add(loginAttribut);
return loginAttribut;
}
// JPA: when this object is linked to multiple other objects, note fetchtype lazy.
@OneToMany(fetch = FetchType.LAZY, mappedBy = "login")
// Hibernate: This ensures the dependant records will be removed by hibernate before the delete query is executed. JPA Cascade doesn't work in this version.
@Cascade(CascadeType.ALL)
public List getLoginAttributs() {
return loginAttributs;
}
public void setLoginAttributs(List loginAttributs) {
this.loginAttributs = loginAttributs;
}*/
public Login() {
}
// JPA mark ID
@Id
// JPA unique field
@Column(name = "id", unique = true, nullable = false)
// Hibernate Type & GeneratedValue for UUID (need to change the type of id to UUID)
//@Type(type = "uuid-char")
//@GeneratedValue(generator = "guid")
// Hibernate GeneratedValue for mysql autoincrement columns INT(10) auto increment, Primary.
@GeneratedValue(strategy = IDENTITY)
public Integer getId() {
return id;
}
public void setId(final Integer id) {
this.id = id;
}
/*
// JPA : when several of this object are linked to the other object
@ManyToOne(fetch = FetchType.LAZY)
// the column that defines the relation, usually contains the ID of other object
@JoinColumn(name = "contextId", unique = true)
public Context getContext() {
return this.context;
}
public void setContext(Context context) {
this.context = context;
}*/
/*
@Type(type = "uuid-char")
// JPA : note usage of updatable & insertable, this allows us to have a column double so we can access the ID instead of the linked object.
@Column(name = "contextId", updatable = false, insertable = false)
public UUID getContextId() {
return contextId;
}
public void setContextId(UUID contextId) {
this.contextId = contextId;
}*/
@Column(name = "login", nullable = false, length = 200)
public String getLogin() {
return this.login;
}
public void setLogin(String login) {
this.login = login;
}
@Column(name = "password", nullable = false, length = 73)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
@Column(name = "admin", nullable = false, length = 1)
// Hibernate type Char(1) values 'Y' or 'N'
@Type(type = "yes_no")
public boolean isAdmin() {
return this.admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
@Column(name = "active", nullable = false, length = 1)
@Type(type = "yes_no")
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
@Column(name = "firstname", nullable = false, length = 200)
public String getFirstname() {
return this.firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Column(name = "lastname", nullable = false, length = 200)
public String getLastname() {
return this.lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
@Column(name = "email", nullable = false)
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
// transient value meaning this won't be saved in the database, in some implementations, it also means it won't be serialized.
/*@Transient
public boolean isLinkedToBerater() {
return (this.getBerater() != null);
}*/
}
===== DAO Interface =====
Now we could use a DAO interface
package be.mentoringsystems.applicationname.dao;
import be.mentoringsystems.applicationname.model.db.Login;
import java.util.List;
/**
*
* @author anthonyarents
*/
public interface LoginDAO {
void saveLogin(final Login login);
void deleteLogin(final Login login);
Login getLoginById(final Integer loginId);
Login getLoginByLogin(final String login);
Login getLoginByLogin(final String loginName, final boolean active);
Login getLoginByLoginWithoutReferences(final String login);
Login getLoginByLoginWithoutReferences(final String login, final boolean active);
Login getLoginByEmail(final String email);
List getAllLogins();
List getAllLoginsBySearch(final String search, final int start, final int limit);
Integer getAllLoginsCountBySearch(final String search);
}
===== DAO Implementation =====
A DAO implementation
package be.mentoringsystems.applicationname.dao.hibernate;
import be.mentoringsystems.applicationname.dao.LoginDAO;
import be.mentoringsystems.applicationname.model.db.Login;
import java.util.List;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
*
* @author anthonyarents
*/
public final class HibernateLoginDAO extends HibernateDaoSupport implements LoginDAO {
public void saveLogin(final Login login) {
// save or update handles the checks to see if the object exists in the database
getHibernateTemplate().saveOrUpdate(login);
}
public void deleteLogin(final Login login) {
// normal delete, a "dummydelete" option is to add a delete flag to login & use save
getHibernateTemplate().delete(login);
}
public Login getLoginById(final Integer loginId) {
final HibernateTemplate template = getHibernateTemplate();
// Hibernate: select by Id
Login login = template.get(Login.class, loginId);
// Hibernate: reuse hibernatetemplate (good for performance) & initialize only the lazy collections you need
//template.initialize(login.getLoginAttributs());
return login;
}
public Login getLoginByEmail(final String loginEmail) {
final HibernateTemplate template = getHibernateTemplate();
// criteria queries
final DetachedCriteria criteria = DetachedCriteria.forClass(Login.class);
// Restrictions = where clause
criteria.add(Restrictions.eq("email", loginEmail));
criteria.add(Restrictions.eq("active", true));
// Order (sorting)
criteria.addOrder(Order.desc("createdOn"));
final List result = template.findByCriteria(criteria);
if(result.isEmpty()) {
return null;
} else {
final Login login = result.get(0);
//template.initialize(login.getBerater());
//template.initialize(login.getLoginAttributs());
//template.initialize(login.getContext());
return login;
}
}
public Login getLoginByLoginWithoutReferences(final String loginName, final boolean active) {
final HibernateTemplate template = getHibernateTemplate();
final DetachedCriteria criteria = DetachedCriteria.forClass(Login.class);
criteria.add(Restrictions.eq("login", loginName));
if(active) {
criteria.add(Restrictions.eq("active", active));
}
criteria.addOrder(Order.desc("createdOn"));
final List result = template.findByCriteria(criteria);
if(result.isEmpty()) {
return null;
} else {
final Login login = result.get(0);
//template.initialize(login.getLoginAttributs());
//template.initialize(login.getContext());
//template.initialize(login.getContext().getContextAttributs());
return login;
}
}
public Login getLoginByLoginWithoutReferences(final String loginName) {
return getLoginByLoginWithoutReferences(loginName, true);
}
public Login getLoginByLogin(final String loginName, final boolean active) {
final HibernateTemplate template = getHibernateTemplate();
final DetachedCriteria criteria = DetachedCriteria.forClass(Login.class);
criteria.add(Restrictions.eq("login", loginName));
if(active) {
criteria.add(Restrictions.eq("active", active));
}
criteria.addOrder(Order.desc("createdOn"));
final List result = template.findByCriteria(criteria);
if(result.isEmpty()) {
return null;
} else {
final Login login = result.get(0);
//template.initialize(login.getBerater());
/*if(login.getBerater() != null) {
template.initialize(login.getBerater().getBeratersForVorgesetzterId());
for(BeraterVorgesetzter beraterVorgesetzter : login.getBerater().getBeratersForBeraterId()) {
template.initialize(beraterVorgesetzter.getBerater());
template.initialize(beraterVorgesetzter.getBerater().getEfpId());
}
}*/
//template.initialize(login.getLoginAttributs());
//template.initialize(login.getContext());
//template.initialize(login.getContext().getContextAttributs());
return login;
}
}
public Login getLoginByLogin(final String loginName) {
return getLoginByLogin(loginName, true);
}
public List getAllLogins() {
final HibernateTemplate template = getHibernateTemplate();
final List result = template.loadAll(Login.class);
for(Login login : result) {
/*if(login.getBerater() != null) {
template.initialize(login.getBerater());
}*/
//template.initialize(login.getLoginAttributs());
//template.initialize(login.getContext());
}
return result;
}
public Integer getAllLoginsCountBySearch(final String search) {
final DetachedCriteria criteria = DetachedCriteria.forClass(Login.class);
if(search != null) {
criteria.add(Restrictions.or(Restrictions.like("login", "%" + search + "%"), Restrictions.like("lastname", "%" + search + "%")));
}
criteria.setProjection(Projections.rowCount());
final List result = getHibernateTemplate().findByCriteria(criteria);
return result.get(0).intValue();
}
public List getAllLoginsBySearch(final String search, final int start, final int limit) {
final HibernateTemplate template = getHibernateTemplate();
final DetachedCriteria criteria = DetachedCriteria.forClass(Login.class);
criteria.addOrder(Order.asc("createdOn"));
if(search != null) {
criteria.add(Restrictions.or(Restrictions.like("login", "%" + search + "%"), Restrictions.like("lastname", "%" + search + "%")));
}
final List result = template.findByCriteria(criteria, start, limit);
for(Login login : result) {
/*if(login.getBerater() != null) {
template.initialize(login.getBerater());
}
template.initialize(login.getLoginAttributs());
template.initialize(login.getContext());*/
}
return result;
}
}
Advanced hibernate criteria queries exist, If you need examples contact me :-).
===== Service Interface =====
package be.mentoringsystems.applicationname.service;
import be.mentoringsystems.applicationname.model.db.Login;
import java.util.List;
/**
*
* @author anthonyarents
*/
public interface LoginService {
void saveLogin(final Login login);
void deleteLogin(final Login login);
Login getLoginById(final Integer loginId);
Login getLoginByLogin(final String login);
Login getLoginByLogin(final String loginName, final boolean active);
Login getLoginByLoginWithoutReferences(final String login);
Login getLoginByLoginWithoutReferences(final String login, final boolean active);
Login getLoginByEmail(final String email);
List getAllLogins();
List getAllLoginsBySearch(final String search, final int start, final int limit);
Integer getAllLoginsCountBySearch(final String search);
}
===== Service Implementation =====
package be.mentoringsystems.applicationname.service.impl;
import be.mentoringsystems.applicationname.dao.LoginDAO;
import be.mentoringsystems.applicationname.model.db.Login;
import be.mentoringsystems.applicationname.service.LoginService;
import java.util.ArrayList;
import java.util.List;
// always use this logger
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
*
* @author anthonyarents
*/
// Spring: using spring Transactional annotation to manage transactions,
// supports = don't need to be in a transaction but can be part of one
@Transactional(propagation = Propagation.SUPPORTS)
public final class LoginServiceImpl implements LoginService {
private transient LoginDAO loginDAO;
private static final Logger LOGGER = Logger.getLogger(LoginServiceImpl.class);
// required = need to be in a transaction, basicly, you want to change/delete/insert the object
@Transactional(propagation = Propagation.REQUIRED)
public void saveLogin(final Login login) {
loginDAO.saveLogin(login);
}
@Transactional(propagation = Propagation.REQUIRED)
public void deleteLogin(final Login login) {
loginDAO.deleteLogin(login);
}
public Login getLoginById(final Integer loginId) {
return loginDAO.getLoginById(loginId);
}
public Login getLoginByLogin(final String login) {
return loginDAO.getLoginByLogin(login);
}
public Login getLoginByLoginWithoutReferences(final String login) {
return loginDAO.getLoginByLoginWithoutReferences(login);
}
public Login getLoginByLogin(final String login, final boolean active) {
return loginDAO.getLoginByLogin(login, active);
}
public Login getLoginByLoginWithoutReferences(final String login, final boolean active) {
return loginDAO.getLoginByLoginWithoutReferences(login, active);
}
public Login getLoginByEmail(final String email) {
return loginDAO.getLoginByEmail(email);
}
public List getAllLogins() {
return loginDAO.getAllLogins();
}
public List getAllLoginsBySearch(final String search, final int start, final int limit) {
return loginDAO.getAllLoginsBySearch(search, start, limit);
}
public Integer getAllLoginsCountBySearch(final String search) {
return loginDAO.getAllLoginsCountBySearch(search);
}
public void setLoginDAO(final LoginDAO loginDAO) {
this.loginDAO = loginDAO;
}
}
===== Presentation (controllers) =====
Do not use DAO classes here! \\
Method signature : ''public ModelAndView methodname(HttpServletRequest hsr, HttpServlerResponse hsr1)'' \\
Use of MappingJacksonJsonView to return a json Object (mapping happens automatically).
package be.mentoringsystems.applicationname.presentation;
import be.mentoringsystems.applicationname.model.db.Login;
import be.mentoringsystems.applicationname.service.LoginService;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.springframework.web.servlet.view.json.MappingJacksonJsonView;
/**
*
* @author anthonyarents
*/
public final class LoginController extends MultiActionController {
private static final String SUCCESS = "success";
private transient LoginService loginService;
private static final Logger LOGGER = Logger.getLogger(LoginController.class);
public ModelAndView getLogin(final HttpServletRequest hsr, final HttpServletResponse hsr1) {
final MappingJacksonJsonView view = new MappingJacksonJsonView();
view.addStaticAttribute(SUCCESS, false);
final Login login = loginService.getLoginByLogin(hsr.getRemoteUser()); // use spring security in the future, hsr.getRemoteUser gives you the loginname but isn't always accurate
if (login != null) {
final Map userMap = new HashMap();
userMap.put("id", login.getId());
userMap.put("admin", login.isAdmin());
userMap.put("login", login.getLogin());
userMap.put("firstname", login.getFirstname());
userMap.put("lastname", login.getLastname());
userMap.put("email", login.getEmail());
view.addStaticAttribute("data", userMap);
view.addStaticAttribute(SUCCESS, true);
}
return new ModelAndView(view);
}
public ModelAndView getAllLogins(final HttpServletRequest hsr, final HttpServletResponse hsr1) {
final MappingJacksonJsonView view = new MappingJacksonJsonView();
view.addStaticAttribute(SUCCESS, false);
//UUID contextId = HelperMethods.getUUID(hsr.getParameter("contextId"));
//final Context context = contextService.getContextById(contextId);
//if (securityService.hasAdminAccess(context)) {
final List logins = loginService.getAllLogins();
view.addStaticAttribute(SUCCESS, true);
view.addStaticAttribute("hits", logins.size());
view.addStaticAttribute("data", logins);
//}
return new ModelAndView(view);
}
public ModelAndView getAllLoginsBySearch(final HttpServletRequest hsr, final HttpServletResponse hsr1) {
int start = 0;
int limit = 20;
if (hsr.getParameter("start") != null && hsr.getParameter("start").length() != 0) {
start = Integer.parseInt(hsr.getParameter("start"));
}
if (hsr.getParameter("limit") != null && hsr.getParameter("limit").length() != 0) {
limit = Integer.parseInt(hsr.getParameter("limit"));
}
final String search = hsr.getParameter("search");
//UUID contextId = HelperMethods.getUUID(hsr.getParameter("contextId"));
//final Context context = contextService.getContextById(contextId);
final MappingJacksonJsonView view = new MappingJacksonJsonView();
view.addStaticAttribute(SUCCESS, false);
//if (securityService.hasAdminAccess(context)) {
final List logins = loginService.getAllLoginsBySearch(search, start, limit);
view.addStaticAttribute(SUCCESS, true);
view.addStaticAttribute("hits", loginService.getAllLoginsCountBySearch(search));
view.addStaticAttribute("data", logins);
//}
return new ModelAndView(view);
}
public void setLoginService(final LoginService loginService) {
this.loginService = loginService;
}
}
====== Further configuration ======
===== applicationname-database.xml =====
add ''applicationname-database.xml'' in ''Other Sources/src/main/resources/''
be.mentoringsystems.applicationname.model.db
be.mentoringsystems.applicationname.model.db
false
false
false
org.hibernate.dialect.MySQL5Dialect
net.bull.javamelody.HibernateBatcherFactory
true
utf8
utf8
===== applicationname-services.xml =====
add ''applicationname-services.xml'' in ''Other Sources/src/main/resources/''
===== applicationname-servlet.xml =====
Add ''applicationname-servlet.xml'' to ''/WEB-INF/'' \\
This file is picked up by the dispatcher servlet of spring so is essentially in a different scope (it can access everything defined in spring context)
loginController
indexController
====== JSP Pages ======
===== Login =====
Add ''login.jsp'' to ''/WEB-INF/jsp'' \\
Login
Login
You are free to change the implementation of the loginpage, \\
you'll find it easier to rely on an old fashioned form submit to login a user, the system will then redirect to app.html (app.jsp)
===== App =====
Add ''app.jsp'' to ''/WEB-INF/jsp'' \\
this should be the index.html of your extjs application
====== Static resources (javascript, css, ...) ======
Don'y use html pages, use jsp like above.
simply place the resource in ''/static/'' or any subfolder there
====== Spring Security ======
Some overrides are needed to make things work the way we want them to :
===== Authentication provider =====
Spring Security needs some convincing to use our own models
package be.mentoringsystems.applicationname.security;
import be.mentoringsystems.applicationname.model.db.Login;
import be.mentoringsystems.applicationname.service.LoginService;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
/**
* Implementation of AuthenticationProvider with support for our login service.
*
* @author anthonyarents
*/
@Transactional(propagation = Propagation.SUPPORTS)
public final class CustomAuthenticationProvider implements AuthenticationProvider {
private transient LoginService loginService;
public void setLoginService(final LoginService loginService) {
this.loginService = loginService;
}
/**
* This method is executed by spring security, it will authenticate a user
* (check if username & password are correct).
*
* @param authentication authentication object supplied by spring security
* @return UsernamePasswordAuthenticationToken (if login worked)
*/
public Authentication authenticate(final Authentication authentication)
final Login user = loginService.loginAsUser(authentication.getPrincipal().toString(), authentication.getCredentials().toString());
final List authorities = getAuthorities(user);
// don't give the password, it would be unprotected !
final User userDetails = new User(authentication.getPrincipal().toString(), "", true, true, true, true, authorities);
return new UsernamePasswordAuthenticationToken(userDetails, userDetails, authorities);
}
// This method can be used to add new roles based on login flags
public List getAuthorities(final Login login) {
final List authorities = new ArrayList();
if (login.isAdmin()) {
authorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
}
authorities.add(new GrantedAuthorityImpl("ROLE_USER"));
return authorities;
}
/**
* This method is used by spring security to determine if spring security
* can use this class to authenticate a UsernamePasswordAuthenticationToken.
*
* @param type class of authenticationtoken
* @return boolean
*/
public boolean supports(final Class extends Object> type) {
boolean result = false;
if (type == UsernamePasswordAuthenticationToken.class) {
result = true;
}
return result;
}
}
===== UserDetailsService =====
Spring Security doesn't use authentication provider for everything.
package be.mentoringsystems.applicationname.security;
import be.mentoringsystems.applicationname.model.db.Login;
import be.mentoringsystems.applicationname.service.LoginService;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
*
* @author anthonyarents
*/
public class UserDetailsServiceImpl implements UserDetailsService {
private transient LoginService loginService;
private static final Logger LOGGER = Logger.getLogger(UserDetailsServiceImpl.class);
public void setLoginService(final LoginService loginService) {
this.loginService = loginService;
}
@Override
public UserDetails loadUserByUsername(String string) throws UsernameNotFoundException, DataAccessException {
// get the user we want to switch to
Login login = loginService.getLoginByLogin(string);
// check if we are allowed to see the user (contexts!)
/*Login admin = securityService.getLoginWithBerater();
if(admin.isAdmin() && !securityService.hasAdminAccess(admin, login.getContext())) {
throw new AccessDeniedException("Admin " + admin.getLogin() + " is not allowed to log in as " + login.getLogin() + " due to context differences");
}
Berater berater = beraterService.getBeraterById(login.getBeraterId());
if(!securityService.hasAccess(admin, berater)) {
throw new AccessDeniedException("User " + admin.getLogin() + " is not allowed to log in as " + login.getLogin() + ".");
}*/
return new User(login.getLogin(), login.getLogin(), true, true, true, true, getAuthorities(login));
}
public List getAuthorities(final Login login) {
final List authorities = new ArrayList();
if (login.isAdmin()) {
authorities.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
}
authorities.add(new GrantedAuthorityImpl("ROLE_USER"));
return authorities;
}
}
===== Json fixes =====
We want a json message telling us we need to login when we do an AJAX request. else spring will redirect to the loginpage & our application will break without telling why. (not needed when polling the server)
==== Custom Access Denied Handler ====
package be.mentoringsystems.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
/**
*
* @author anthonyarents
*/
public class CustomAccessDeniedHandler extends AccessDeniedHandlerImpl {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
final String jsonHeader = request.getHeader("X-Requested-With");
if (jsonHeader != null) {
response.setStatus(SaveContextOnUpdateOrErrorResponseWrapper.SC_UNAUTHORIZED);
response.setHeader("Location", null);
response.setContentType("application/json;charset=UTF-8");
response.getOutputStream().print("{\"success\" : false, \"data\" : [], \"error\" : \"LOGIN REQUIRED\"}");
} else {
super.handle(request, response, accessDeniedException);
}
}
}
==== Custom Authentication Entry Point ====
package be.mentoringsystems.applicationname.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
/**
*
* @author anthonyarents
*/
public class CustomAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
final String jsonHeader = request.getHeader("X-Requested-With");
if (jsonHeader != null) {
response.setStatus(SaveContextOnUpdateOrErrorResponseWrapper.SC_UNAUTHORIZED);
response.setHeader("Location", null);
response.setContentType("application/json;charset=UTF-8");
response.getOutputStream().print("{\"success\" : false, \"data\" : [], \"error\" : \"LOGIN REQUIRED\"}");
} else {
super.commence(request, response, authException);
}
}
}
===== applicationname-security.xml =====
add ''applicationname-security.xml'' in ''Other Sources/src/main/resources/''