It's only the simpliest Struts2-Spring-Hibernate web application which only has a login function. I will call it SSH which is apparently different from the one appeared in Linux.
I assume the installation of JDK6.0 and Tomcat5.0 and their environmental variables' path setting are all correctly deployed.
This is developed under Vista and Lomboz Eclipse. The reason I use Lomboz Eclipse is it's a totally free JEE Eclipse which is not like MyEclipse.
I strongly recommend JEE novice using Lomboz Eclipse as their development tools. All the configuration about Strut2, Spring or Hibernate will be done manually. Although it may take time at beginning, the process of adding 3rd party jars and editing related XML files such as struts.xml and applicationContext.xml can reallly help understanding the SSH architecture.
Before everything getting start, configure Lomboz Eclipse to make sure it has Tomcat plugin because unlike MyEclipse, Lomboz Eclipse doesn't have Tomcat function. The plugin is on this web site:
http://www.eclipsetotale.com/tomcatPlugin.html
Make suere it is
tomcatPluginV321.zip and the others do not work under Lomboz Eclipse3.3.
Unzip and place the plugin under %Your Lomboz Eclipse directory%\plugins
Start the eclipse, you will see 3 tomcat icons in the tool bar and 'tomcat' in menu bar, this means your tomcat plugin has been inserted.
Click Window -> Preferences
In the new popup configuration window, select 'tomcat' in the left selection list. If you don't have this 'tomcat' option, it means your tomcat plugin is not compatible with your current eclipse, you must remove the incompatible plugin and download another tomcat plugin for your specific eclipse which is not Lomboz Eclipse3.3.
Then, select Version 6.x on the right panel, click browse and pick your own %TOMCAT_HOME% directory. Then ecplise will automatically select Context declaration mode for you in the blue square. Don't change it! It will cause a lot of trouble if you change it without deep understanding about Server.xml.
Now it is worth to mention that your %TOMCAT_HOME% will be better not in your system disk like C:. In my case, I only unzip tomcat and place it under F:
Because sometimes, eclipse needs to change server.xml under %TOMCAT_HOME% and if the current user in windows is not allowed to write in system disk, it will cause problem. For example, Vista doesn't allow eclipse to change server.xml if it is placed under windows' installation disk.
Click '+' left to 'Tomcat' and select 'JVM Settings'
First, select JRE which is jre6 and then add tools.jar and dt.jar to classpath and rt.jar to boot path. tool.jar and dt.jar are under JDK's lib directory and rt.jar is under JRE's lib directory. It's quite nessary to add them first in Lomboz Eclipse. Without those JARs, after you starting tomcat, and trying to open webpage http://127.0.0.1/****, it will have page not found error.
Double check the Java configuration, click '+' left to Java and select 'Installed JREs'. Click Add button in the right panel and add your own JRE path like showing in the red square.
Select 'Compiler' under 'Java' and in the right panel, make sure the compiler is 6.0 like in the red square.
Now, all the beginning deployment is done.
Now, let's start newing a web project: File -> New -> Other..
In the new popup window, make sure you select 'dynamic web project' and click 'next'.
Create the project name like 'loginbystruts' and make sure the tomcat configuration is just same as in 2 following red squares:
You can click 'Finish' by defaulting all the following setting or 'Next' to have your own settings before creating the project.
Then you will have following directory structure like this:
Create index.jsp under 'WebContent':
Here is the simple hello world index.jsp:
1 <%@ page language="java" contentType="text/html; charset=UTF-8"
2 pageEncoding="UTF-8"%>
3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7 <title>SSH first example</title>
8 </head>
9 <body>
10
11 <h1>Hello World!</h1>
12 </body>
13 </html>
Now it's time to configure the tomcat server:
Right click 'loginbystruts' and 'Profile As' -> 'Profile on Server'
Then check out the popup window and make sure the selection is the same as in the following red squares:
Then click 'Finish' defaulting all other settings.
If it is the first time you run Lomboz Eclipse, then in the 'Project Explore', there will be a 'server' appeared after setting 'profile on server'
Open server.xml and check the following piece of code:
1 <Context docBase="loginbystruts" path="/loginbystruts" reloadable="true" source="org.eclipse.jst.jee.server:loginbystruts"/>
This means now 'loginbystruts' is added and it's time to start the server.
You can click the tomcat icon on the menu bar or click the button in the following red circle:
After successfully turning on the server, open web browser and enter the address:
http://localhost:8080/loginbystruts/index.jsp
If you have any problem in showing the index.jsp, carefully check all the setup and re-do.
Now it's time to build SSH architecture. First of all, all the necessary lib jars must be added into 'loginbystruts\WebContentWEB-INF\lib'.
Import external library cannot help in SSH deployment, all the JARs must be directly copied under 'lib'.
There are lots of questions online asking about various exceptions. Most of them can be solved by including the correct and compatible JARs.
Turn back to eclipse and check:
Create login.jsp under 'WebContent':
1 <%@ page language="java" contentType="text/html; charset=UTF-8"
2 pageEncoding="UTF-8"%>
3 <%@ taglib prefix="s" uri="/struts-tags"%>
4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
5 <html>
6 <head>
7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
8 <title>Login</title>
9 </head>
10 <body>
11 <%-- action="login" actually can work with this error. --%>
12 <s:form action="login">
13 <s:textfield name="user.username" label="username"></s:textfield>
14 <s:password name="user.password" label="password"></s:password>
15 <s:submit lable="submit"></s:submit>
16 <s:reset lable="reset"></s:reset>
17 </s:form>
18 </body>
19 </html>
Because it's the first example of SSH, no other fancy CSS included.
Several packages and classes are constructed as follows:
Here is an small error in which is only related to the Lomboz Eclipse Jsp editor, and it is actually using correct Struts2 grammar in login.jsp, so leave it alone:
Create LoginAction.java, User.java, UserDao.java, UserDaoImpl.java, UserService.java, UserServiceImpl.java.
Notice: UserDao.java and UserService.java are interface. UserDaoImpl extends UserDao and UserServiceImpl extendss UserService; meanwhile LoginAction extends ActionSuport.
Make sure they are all in different packages something like this:
com.ssh.action
|__ LoginAction.java
com.ssh.bean
|__ User.java
com.ssh.dao
|__ UserDao.java
com.ssh.dao.impl
|__ UserDaoImpl.java
com.ssh.service
|__ UserService.java
com.ssh.service.impl
|__ UserServiceImpl.java
The detail idea behind this structure is typical in SSH development but not included in this post.
User.java:
1 package com.ssh.bean;
2
3 public class User {
4 private long id;
5 private String username;
6 private String password;
7 public long getId() {
8 return id;
9 }
10 public void setId(long id) {
11 this.id = id;
12 }
13 public String getUsername() {
14 return username;
15 }
16 public void setUsername(String username) {
17 this.username = username;
18 }
19 public String getPassword() {
20 return password;
21 }
22 public void setPassword(String password) {
23 this.password = password;
24 }
25 }
UserService.java
1 package com.ssh.service;
2
3 import java.util.List;
4 import com.ssh.bean.User;
5
6 public interface UserService {
7 public void save(User user);
8 public void remove(User user);
9 public User findUserById(long id);
10 public List<User> findAll();
11 public void update(User user);
12 }
UserDao.java
1 package com.ssh.dao;
2
3 import com.ssh.bean.User;
4 import java.util.List;
5 public interface UserDao {
6 public void save(User user);
7 public void remove(User user);
8 public User findUserById(long id);
9 public List<User> findAll();
10 public void update(User user);
11 }
12
Before implementing UserService and UserDao, now it's time to configure database.
I strongly recommend create your table under OO idea which means you don't have to create tables in database directly but only by writing Java code with importing Hibernate Jars.
Create hibernate.cfg.xml directly under 'Java Resource: src':
hibernate.cfg.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE hibernate-configuration PUBLIC
3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
5
6 <hibernate-configuration>
7 <session-factory>
8 <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/blogjava</property>
9 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
10 <property name="hibernate.connection.username">root</property>
11 <property name="hibernate.connection.password">12345678</property>
12 <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
13 <property name="hibernate.show_sql">true</property>
14
15 <mapping resource="com/ssh/bean/User.hbm.xml"/>
16 </session-factory>
17 </hibernate-configuration>
As we can see, I am using mysql and there is a schema named "blogjava"
I am using com.mysql.jdbc.Driver as my mysql driver and the database user is 'root' and password is '12345678'. Change them according to your database username and password, change the port number if you have changed your port number already.
The reason and details are not revealed in this post. As a first hello world example, just do it.
Create User.hbm.xml directly under package com.ssh.bean which is the same package with User.java
User.hbm.xml
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE hibernate-mapping PUBLIC
3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
5 <hibernate-mapping>
6 <class name="com.ssh.bean.User" table="user">
7 <id name="id" type="java.lang.Long" column="id">
8 <generator class="increment"></generator>
9 </id>
10 <property name="username" type="string" column="name" length="200"></property>
11 <property name="password" type="string" column="password" length="200"></property>
12 </class>
13 </hibernate-mapping>
Now it's time to create table under schema "blogjava", in your specific case, you can change 'blogjava' to any names which you have already created in your own database.
Create new package com.ssh.test and create new java file ExportDB.java under this package:
1 package com.ssh.test;
2
3 import org.hibernate.cfg.Configuration;
4 import org.hibernate.tool.hbm2ddl.SchemaExport;
5
6 public class ExportDB {
7 public static void main(String[] args){
8 Configuration cfg = new Configuration().configure();
9 SchemaExport export = new SchemaExport(cfg);
10 export.create(true, true);
11 }
12 }
Run this class and a table named "user" is created under 'blogjava'. If it runs successfully, there are some print out in console:
drop table if exists user
create table user (id bigint not null, name varchar(200), password varchar(200), primary key (id))
You can download free version MySql Developer from MySQL and visualize your database development. By openning "MySQL Query Browser", we can see:
At this time, I insert a new user into this table by following code:
Create Client.java under package com.ssh.test
1 package com.ssh.test;
2
3 import org.hibernate.Session;
4 import org.hibernate.SessionFactory;
5 import org.hibernate.cfg.Configuration;
6 import com.ssh.bean.User;
7
8 public class Client {
9
10 /**
11 * @param args
12 */
13 public static void main(String[] args) {
14 // TODO Auto-generated method stub
15 Configuration cfg = new Configuration().configure();
16 // Create a session factory;
17 SessionFactory sessionfactory = cfg.buildSessionFactory();
18 Session session = null;
19 try{
20 session = sessionfactory.openSession();
21 session.beginTransaction();
22
23 User user = new User();
24 user.setUsername("Brooklyn");
25 user.setPassword("12345");
26
27 session.save(user);
28
29 session.getTransaction().commit();
30 }catch(Exception e){
31 session.getTransaction().rollback();
32 e.printStackTrace();
33 }finally{
34 if(session != null){
35 if(session.isOpen())
36 session.close();
37 }
38 }
39 }
40 }
By running this piece of code, a new user with username 'Brooklyn' and password '12345' is inserted into table 'user'.
Now we turn back to implement UserDaoImpl.java and UserServiceImpl.java:
UserDaoImpl.java
1 package com.ssh.dao.impl;
2
3 import java.util.List;
4 import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
5 import com.ssh.bean.User;
6 import com.ssh.dao.UserDao;
7
8 public class UserDaoImpl extends HibernateDaoSupport implements UserDao {
9 @SuppressWarnings("unchecked")
10 @Override
11 public List<User> findAll() {
12 // TODO Auto-generated method stub
13 String hql = "from User user order by user.id desc";
14 return (List<User>) this.getHibernateTemplate().find(hql);
15 }
16
17 @Override
18 public User findUserById(long id) {
19 // TODO Auto-generated method stub
20 User user = (User) this.getHibernateTemplate().get(User.class, id);
21 return user;
22 }
23
24 @Override
25 public void remove(User user) {
26 // TODO Auto-generated method stub
27 this.getHibernateTemplate().delete(user);
28 }
29
30 @Override
31 public void save(User user) {
32 // TODO Auto-generated method stub
33 this.getHibernateTemplate().save(user);
34 }
35
36 @Override
37 public void update(User user) {
38 // TODO Auto-generated method stub
39 this.getHibernateTemplate().update(user);
40 }
41 }
Notice: UserDaoImpl also extends HibernateDaoSupport which has a member function getHibernateTemplate. This member function simplifies the development a lot.
UserServiceImpl.java
1 package com.ssh.service.impl;
2
3 import java.util.List;
4 import com.ssh.bean.User;
5 import com.ssh.dao.UserDao;
6 import com.ssh.service.UserService;
7
8 public class UserServiceImpl implements UserService {
9
10 private UserDao userDao;
11
12 public UserDao getUserDao() {
13 return userDao;
14 }
15
16 public void setUserDao(UserDao userDao) {
17 this.userDao = userDao;
18 }
19
20 @Override
21 public List<User> findAll() {
22 // TODO Auto-generated method stub
23 return this.userDao.findAll();
24 }
25
26 @Override
27 public User findUserById(long id) {
28 // TODO Auto-generated method stub
29 return this.userDao.findUserById(id);
30 }
31
32 @Override
33 public void remove(User user) {
34 // TODO Auto-generated method stub
35 this.userDao.remove(user);
36 }
37
38 @Override
39 public void save(User user) {
40 // TODO Auto-generated method stub
41 this.userDao.save(user);
42 }
43
44 @Override
45 public void update(User user) {
46 // TODO Auto-generated method stub
47 this.userDao.update(user);
48 }
49
50 }
51
As we can see there is a private object UserDao userDao in UserServiceImpl, this means AOP must be applied in applicationContext.xml. It's quite typical in Spring struture.
As I mentioned before, in this post, I don't talk about why these interfaces, classes and xml files are created. As a typical SSH application, they are all necessary.
Under 'Java Resource: src', create struts.xml:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!DOCTYPE struts PUBLIC
3 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
4 "http://struts.apache.org/dtds/struts-2.0.dtd">
5 <struts>
6 <package name="sshlogin" extends="struts-default">
7 <action name="login" class="loginAction" method="login">
8 <result name="success">/user.jsp</result>
9 <result name="input">/login.jsp</result>
10 </action>
11 </package>
12 </struts>
Notice: method="login" means in LoginAction.java there must be a method named 'login'.
Under WebContent/WEB-INF/applicationContext.xml for configuring Spring bean:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="
5 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
6
7 <!-- <bean/> definitions here -->
8 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
9 <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
10 <property name="url" value="jdbc:mysql://localhost:3306/blogjava"></property>
11 <property name="username" value="root"></property>
12 <property name="password" value="112358"></property>
13 <property name="maxActive" value="100"></property>
14 <property name="maxIdle" value="30"></property>
15 <property name="maxWait" value="500"></property>
16 <property name="defaultAutoCommit" value="true"></property>
17 </bean>
18 <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
19 <property name="dataSource" ref="dataSource"></property>
20 <property name="hibernateProperties">
21 <props>
22 <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
23 <prop key="show_sql">true</prop>
24 </props>
25 </property>
26 <property name="mappingResources">
27 <list>
28 <value>com/ssh/bean/User.hbm.xml</value>
29 </list>
30 </property>
31 </bean>
32
33 <bean id="userDao" class="com.ssh.dao.impl.UserDaoImpl" scope="singleton">
34 <property name="sessionFactory">
35 <ref bean="sessionFactory"/>
36 </property>
37 </bean>
38
39 <bean id="userService" class="com.ssh.service.impl.UserServiceImpl">
40 <property name="userDao">
41 <ref bean="userDao"/>
42 </property>
43 </bean>
44
45 <bean id="loginAction" class="com.ssh.action.LoginAction" scope="prototype">
46 <property name="userService">
47 <ref bean="userService"/>
48 </property>
49 </bean>
50
51 </beans>
Beware that the last bean's id="loginAction" must be same in struts.xml:
1 <action name="login" class="loginAction" method="login">
action name="login" must be same action name in login.jsp:
1 <s:form action="login">
2 <s:textfield name="user.username" label="username"></s:textfield>
3 <s:password name="user.password" label="password"></s:password>
4 <s:submit lable="submit"></s:submit>
5 <s:reset lable="reset"></s:reset>
6 </s:form>
class="loginAction" must be same in applicationContext.xml:
1 <bean id="loginAction" class="com.ssh.action.LoginAction" scope="prototype">
2 <property name="userService">
3 <ref bean="userService"/>
4 </property>
5 </bean>
Now, I can finish LoginAction.java:
1 package com.ssh.action;
2
3 import java.util.List;
4 import com.opensymphony.xwork2.ActionSupport;
5 import com.ssh.bean.User;
6 import com.ssh.service.UserService;
7
8 public class LoginAction extends ActionSupport {
9 private UserService userService;
10 private User user;
11 public void setUserService(UserService userService) {
12 this.userService = userService;
13 }
14
15 public User getUser() {
16 return user;
17 }
18
19 public void setUser(User user) {
20 this.user = user;
21 }
22
23 public String login(){
24 List<User> users = this.userService.findAll();
25 if(users == null || users.isEmpty())
26 return INPUT;
27 for(int i=0; i<users.size(); i++){
28 User u = users.get(i);
29 if(u.getUsername().equals(user.getUsername())){
30 if(u.getPassword().equals(user.getPassword()))
31 return SUCCESS;
32 else
33 continue;
34 }else
35 continue;
36 }
37 return INPUT;
38 }
39 }
40
Create user.jsp under WebContent/user.jsp
1 <%@ page language="java" contentType="text/html; charset=UTF-8"
2 pageEncoding="UTF-8"%>
3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
4 <html>
5 <head>
6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7 <title>User</title>
8 </head>
9 <body>
10 <h2>User Login Successfully</h2>
11 </body>
12 </html>
Finally, don't forget configure WebContent/WEB-INF/web.xml:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns="http://java.sun.com/xml/ns/javaee"
4 xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
6 id="WebApp_ID" version="2.5">
7 <display-name>loginbystruts</display-name>
8 <filter>
9 <filter-name>struts2</filter-name>
10 <filter-class>
11 org.apache.struts2.dispatcher.FilterDispatcher
12 </filter-class>
13 </filter>
14 <filter-mapping>
15 <filter-name>struts2</filter-name>
16 <url-pattern>/*</url-pattern>
17 </filter-mapping>
18 <listener>
19 <listener-class>
20 org.springframework.web.context.ContextLoaderListener
21 </listener-class>
22 </listener>
23 </web-app>
Now, with everyhing has been configured, I can turn on Tomcat server successfully. If you have any exception during Tomcat startup, check carefully with the Exception information, in most of the cases, mis-typing, forgeting configure web.xml, struts.xml, applicationContext.xml and missing JARs are the most frequent probrems.
Open web browser with address "http://localhost:8080/loginbystruts/login.jsp"
Because it's only a test of SSH structure, I didn't writer validators and interceptors. Neither I didn't write errorfield.
I only introduce the simpliest success condition:
Now, it turn to user.jsp successfully. If type wrong password or username doesn't exist, it turn back to login.jsp:
Here is the final file structure:
src
|
com.ssh.action
| |__ LoginAction.java
com.ssh.bean
| |__ User.java
| |__ User.hbm.xml
com.ssh.dao
| |__ UserDao.java
| com.ssh.dao.impl
| |__ UserDaoImpl.java
com.ssh.service
| |__ UserService.java
| com.ssh.service.impl
| |__ UserServiceImpl.java
com.ssh.test
| |__ ExportDB.java
| |__ Client.java
|__ struts.xml
|__ hibernate.cfg.xml // this is not necessary. It is only for POJO ExportDB and Client. Its functionality is actually replaced
// by applicationContext.xml
WebContent // This is same as WebRoot in MyEclipse configuration.
|__ WEB-INF
| |__ applicationContext.xml // this is the center of all SSH structure.
| |__ web.xml
|__ index.jsp
|__ login.jsp
|__ user.jsp
I will introduce errorfield, validators and interceptors later.