struts2.3.24 + spring4.1.6 + hibernate4.3.11 + mysql5.5.25 development environment construction and related instructions.
1. Goal
1. Build a traditional ssh development environment and run it successfully (insert, query)
2. Understand the configuration of c3p0 connection pool
3. Understand the secondary cache of hibernate and verify
4. Understand the configuration of spring things and verify
5. Understand spring's IOC (dependency injection), hand over the action object (bean) of struts2 to spring management, custom beans, etc., and verify
6. Understand spring aop (section-oriented programming), and write custom section functions to verify the results
2. Preparation
Development environment: eclipse for java ee; mysql5.5.25; jdk1.7.0_79; navicat10.1.7 (optional);
Create a database demo:
/*Navicat MySQL Data TransferSource Server : localhost_3306Source Server Version : 50519Source Host : localhost:3306Source Database : demoTarget Server Type : MYSQLTarget Server Version : 50519File Encoding : 65001Date: 2016-01-09 23:36:02*/SET FOREIGN_KEY_CHECKS=0;-- ------------------------------- Table structure for `user`-- --------------------------------DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `account` varchar(200) NOT NULL, `name` varchar(200) NOT NULL, `address` varchar(1000) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Create a new web project, the directory structure is as follows:
Prepare the jar package and put it in the WEB-INF lib directory (if you are interested, you can use maven to manage the process, but sometimes it is very slow to download the jar package...)
Related jar packages can be found in the downloaded struts, spring, and hibernate. Here is a reference. Some of them can be deleted, such as the jar packages in the spring mvc part:
3. Configure web.xml
Configure a struts2 filter to map all *.action requests, and are handled by the StrutsPrepareAndExecuteFilter object;
Configure the context-param parameter and specify the path of the spring configuration file. The parameters in <context-param> can be obtained by using ServletContext.getInitParameter ("param-name");
Configuring listener is mainly to read applicationContext.xml configuration file information, create beans and other initialization work;
<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>SSH</display-name> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>*.action</url-pattern> </filter-mapping> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list></web-app>
4. Configure applicationContext.xml
Configure automatic scanning of @Repostory, @Service and other annotations under the ssh package and generate corresponding beans;
Configure the data source (jdbc connection pool is c3p0, you can refer to the detailed configuration of c3p0). The main function of the connection pool is to quickly provide connection and reuse it. It does not require each destruction and creation. It requires configuration of username, password, maximum number of connections, minimum number of connections, initial number of connections and other related parameters;
Configure sessionFactory (you can refer to the detailed configuration of hibernate, where you configure to enable level 2 cache), the main function is to provide session and execute SQL statements; here we will use HibernateTemplate to operate the database to facilitate physical control of spring; ps, the mapping between classes and database tables should also be configured in the hibernate configuration;
Configure the transaction manager bean as HibernateTransactionManager, and initialize the member attribute sessionFactory to the sessionFactory bean configured previously;
Configure the propagation characteristics of the transaction, and configure a section to refer to it, and conduct transaction control of all add, delete, update, and save methods under all ssh.service packages and subpackages. You can also configure transaction propagation behavior and other parameters;
Finally, there is a custom aop related configuration, which applies custom section 'myAop' to control all methods starting with tests under ssh.aop.AopTest, and the results will be verified later;
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <!-- scans the classpath for annotated components (including @Repostory and @Service that will be auto-registered as Spring beans --> <context:component-scan base-package="ssh" /> <!--Support data source--> <bean name="dataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/demo" /> <property name="user" value="root" /> <property name="password" value="root" /> <property name="acquireIncrement" value="1"></property> <property name="initialPoolSize" value="80"></property> <property name="maxIdleTime" value="60"></property> <property name="maxPoolSize" value="80"></property> <property name="minPoolSize" value="30"></property> <property name="acquireRetryDelay" value="1000"></property> <property name="acquireRetryAttempts" value="60"></property> <property name="breakAfterAcquireFailure" value="false"></property> <!-- If Too many connections appear, please note that if you modify the configuration file my.ini of mysql to increase the maximum number of connections (see the current connection command: show processlist) --> </bean> <bean id="sessionFactory"> <property name="dataSource" ref="dataSource" /> <property name="hibernateProperties"> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="current_session_context_class">thread</prop> <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.use_second_level_cache">true</prop> <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhcacheRegionFactory</prop> <prop key="hibernate.cache.use_query_cache">true</prop> <prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</prop> </prop> </props> </property> <property name="mappingLocations"> <list> <value>classpath:ssh/model/User.hbm.xml</value> </list> </property> <!-- <property name="annotatedClasses"> <list> <value>ssh.model.User</value> </list> </property> --> </bean> <!-- Configuring Transaction Manager--> <bean id="transactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- Propagation Characteristics of Transaction-Manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> <tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pcMethod" expression="execution(* ssh.service..*.*(..))" /> <aop:advisor pointcut-ref="pcMethod" advice-ref="txadvice" /> </aop:config> <!-- Custom aop processing test--> <bean id="aopTest"></bean> <bean id="myAop"></bean> <aop:config proxy-target-class="true"> <aop:aspect ref="myAop"> <aop:pointcut id="pcMethodTest" expression="execution(* ssh.aop.AopTest.test*(..))"/> <aop:before pointcut-ref="pcMethodTest" method="before"/> <aop:after pointcut-ref="pcMethodTest" method="after"/> </aop:aspect> </aop:config> </beans>
5. Configure struts.xml
Configure the structures.objectFactory constant to spring, indicating that the action is obtained by the bean through spring;
Configure the result type to "json", and you can also configure other things. Here, for the convenience of front-end and back-end data interaction, it is configured in json format;
Configure two actions, addUser and queryAllUser;
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <constant name="struts.objectFactory" value="spring"/> <constant name="struts.enable.DynamicMethodInvocation" value="false" /> <constant name="struts.devMode" value="false" /> <package name="default" extends="struts-default,json-default"> <global-results> <result type="json"> <param name="root">json</param> <param name="contentType">text/html</param> </result> </global-results> <action name="addUser" method="addUser"> <result>.</result> </action> <action name="queryAllUser" method="queryAllUser"> <result>.</result> </action> </package> <!-- Add packages here --></struts>
6. Write relevant code
Notes:
dao inherits the HibernateDaoSupport class, and all database-related operations are operated by hibernateTemplate;
Add corresponding annotations to the dao layer, service layer, and action, and register as spring beans;
The attached code is as follows:
UserAction.java
package ssh.action;import java.io.PrintWriter;import java.util.List;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.log4j.Logger;import org.apache.struts2.ServletActionContext;import org.springframework.stereotype.Controller;import ssh.aop.AopTest;import ssh.model.User;import ssh.service.UserService;import com.google.gson.Gson;@Controllerpublic class UserAction { Logger logger = Logger.getLogger(UserAction.class); @Resource private UserService userService; @Resource private AopTest aopTest; public void addUser(){ PrintWriter out = null; try{ HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); response.setContentType("text/html;charset=UTF-8"); String account = request.getParameter("account"); String name = request.getParameter("name"); String address = request.getParameter("address"); User user = new User(); user.setAccount(account); user.setAddress(address); user.setName(name); userService.add(user); out = response.getWriter(); out.write(new Gson().toJson("success")); } catch(Exception e){ e.printStackTrace(); logger.error(e.getMessage()); if(out != null) out.write(new Gson().toJson("fail")); } finally{ out.flush(); out.close(); } } public void queryAllUser(){ PrintWriter out = null; aopTest.test1(); aopTest.test2(); //logger.error("i"); try { HttpServletResponse response = ServletActionContext.getResponse(); response.setContentType("text/html;charset=UTF-8"); Gson gson = new Gson(); List<User> userList= userService.queryAllUser(); String gsonStr = gson.toJson(userList); out = response.getWriter(); out.write(gsonStr); } catch (Exception e) { e.printStackTrace(); logger.error(e.getMessage()); if(out != null) out.write(new Gson().toJson("fail")); } finally{ out.flush(); out.close(); } }}AopTest.java
package ssh.aop;public class AopTest { public void test1(){ System.out.println("AopTest test1 method is running~"); } public void test2(){ System.out.println("AopTest test2 method is running~"); }}MyAop.java
package ssh.aop;public class MyAop { public void before(){ System.out.println("befor~"); } public void after(){ System.out.println("after~"); }}BaseDao.java
package ssh.dao.base;import javax.annotation.Resource;import org.hibernate.SessionFactory;import org.springframework.orm.hibernate4.support.HibernateDaoSupport;public class BaseDao extends HibernateDaoSupport{ @Resource public void setMySessionFactory(SessionFactory sessionFactory){ this.setSessionFactory(sessionFactory); }}UserDao.java
package ssh.dao;import java.util.ArrayList;import java.util.List;import org.springframework.orm.hibernate4.HibernateTemplate;import org.springframework.stereotype.Repository;import ssh.dao.base.BaseDao;import ssh.model.User;@Repositorypublic class UserDao extends BaseDao{ public void add(User user){ this.getHibernateTemplate().save(user); } @SuppressWarnings("unchecked") public List<User> queryAllUser(){ List<User> users = new ArrayList<User>(); HibernateTemplate hibernateTemplate = this.getHibernateTemplate(); hibernateTemplate.setCacheQueries(true); users = (List<User>) hibernateTemplate.find("from User"); hibernateTemplate.setCacheQueries(false); return users; }}User.java
package ssh.model;import java.io.Serializable;public class User implements Serializable{ /** * */ private static final long serialVersionUID = -6190571611246371934L; private Long id; private String account; private String name; private String address; public String getAccount() { return account; } public String getName() { return name; } public String getAddress() { return address; } public void setAccount(String account) { this.account = account; } public void setName(String name) { this.name = name; } public void setAddress(String address) { this.address = address; } /** * @return the id */ public Long getId() { return id; } /** * @param id the id to set */ public void setId(Long id) { this.id = id; }}User.hbm.xml
<?xml version="1.0"?><!-- ~ Hibernate, Relational Persistence for Idiomatic Java ~ ~ Copyright (c) 2010, Red Hat Inc. or third-party contributers as ~ indicated by the @author tags or express copyright attribute ~ statements applied by the authors. All third-party contributions are ~ distributed under license by Red Hat Inc. ~ ~ This copyrighted material is made available to anyone wishing to use, modify, ~ copy, or redistribute it subject to the terms and conditions of the GNU ~ Lesser General Public License, as published by the Free Software Foundation. ~ ~ This program is distributed in the hope that it will be useful, ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License ~ for more details. ~ ~ You should have received a copy of the GNU Lesser General Public License ~ along with this distribution; if not, write to: ~ Free Software Foundation, Inc. ~ 51 Franklin Street, Fifth Floor ~ Boston, MA 02110-1301 USA --><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"><hibernate-mapping package="ssh.model"> <class name="User" table="user"> <cache usage="read-write"/> <id name="id" column="id"> <generator/> </id> <property name="account" type="java.lang.String" column="account"/> <property name="name" type="java.lang.String" column="name"/> <property name="address" type="java.lang.String" column="address"/> </class></hibernate-mapping>
UserService.java
package ssh.service;import java.util.List;import javax.annotation.Resource;import org.springframework.stereotype.Service;import ssh.dao.UserDao;import ssh.model.User;@Servicepublic class UserService { @Resource private UserDao userDao = new UserDao(); public List<User> queryAllUser(){ return userDao.queryAllUser(); } public void add(User user){ userDao.add(user); }}index.jsp (remember to add jquery library)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Insert title here</title><style>.mt20{ margin-top: 20px;}</style></head><body><div style="text-align: center;"> <div><label>Account: </label><input id="account" type="text"/></div> <div><label>Name: </label><input id="name" type="text"/></div> <div><label>Address: </label><input id="address" type="text"/></div> <div><button id="addUser" >Add</button></div><h3>User List: </h3><ul id="userList"></ul><script type="text/javascript" src="js/jquery-1.11.1.min.js"></script><script> $(function() { $.ajax({ url : 'queryAllUser.action', type : 'post', dataType : 'json', success : function(data) { try { for(var i = 0; i < data.length; i++){ $("#userList").append("<li><span style='color:red'>id="+data[i].id+"</span>,account="+data[i].account+",name="+data[i].name+",address="+data[i].address+"</li>"); } } catch (e) {}; } , error : function(e) { alert("sys error"); } }); $("#addUser").on("click", function() { var account = $("#account").val(); var name = $("#name").val(); var address = $("#address").val(); $.ajax({ url : 'addUser.action', type : 'post', dataType : 'json', data : { account : account, name : name, address : address }, success : function(data) { try { $("#userList").append("<li>account="+account+",name="+name+",address="+address+"</li>"); alert("added successfully"); } catch (e) { } }, error : function(e) { alert("sys error"); } }); }); }); });</script></body></html>7. Verification results
Go back to the beginning, start to get familiar with relevant technologies and verify the results
1. Build a traditional ssh development environment and run it successfully (insert, query)
The following figure: Query and add users successfully;
2. Understand the configuration of c3p0 connection pool
Database connections are expensive resources, and opening and closing consumes performance. Therefore, they can be managed with a connection pool, initializing several connections and reusing them, rather than creating a closing repeatedly, which is a bit similar to a thread pool;
The configuration is as follows. To reasonably configure the minimum and maximum number of connections according to the actual project situation, please refer to the link for the detailed meaning of each parameter.
In addition, it is very simple to verify the connection number configuration. You can write a program to verify it yourself. For example, when the maximum number of connections is 10, you can write a program to verify it. After opening 10 connections, the 11th connection will be in a waiting state and cannot be obtained. Therefore, you must configure the number of connections reasonably according to the situation, otherwise it may affect the application performance;
<!--Support data source--> <bean name="dataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/demo" /> <property name="user" value="root" /> <property name="password" value="root" /> <property name="acquireIncrement" value="1"></property> <property name="initialPoolSize" value="80"></property> <property name="maxIdleTime" value="60"></property> <property name="maxPoolSize" value="80"></property> <property name="minPoolSize" value="30"></property> <property name="acquireRetryDelay" value="1000"></property> <property name="acquireRetryAttempts" value="60"></property> <property name="breakAfterAcquireFailure" value="false"></property> <!-- If Too many connections appear, please note that modify mysql's configuration file my.ini to increase the maximum number of connections configuration items (see the current connection command: show processlist) --> </bean>
3. Understand the secondary cache of hibernate and verify
The first-level cache of hibernate refers to the session-wide cache, which is enabled by default. The second-level cache is the sessionFactory range cache. When configuring the sessionFactory, we have configured the second-level cache as ehcache. Next, we verify the effect and query the user operation. We found that the first query will operate the database, print the SQL statement, and after refreshing the page, we found that the query was successful and no SQL statement was printed. As shown in the figure below, we can see that the secondary cache work is OK;
4. Understand the configuration of spring things and verify
The so-called transaction control principle is the same, which is to ensure atomicity, consistency, isolation, and persistence. When programming jdbc, it is controlled by itself. Set autocommit=false to not automatically submit, and then start writing specific database operations. When an exception occurs, rollback, otherwise commit; in fact, the control principle of spring on things is similar, and it is added with some packaging, configuration, etc., which is more convenient, such as controlling different methods in the service layer;
Verification is very simple. Write two insertion operations in a method at the service level (note that the method name must comply with the rules configured in the spring configuration file), throw an exception in the middle, and then execute it. If you find that the first user is inserted successfully, it means that the transaction control is invalid, otherwise it is OK;
5. Understand spring's IOC (dependency injection), hand over the action object (bean) of struts2 to spring management, custom beans, etc., and verify
If you observe carefully, in the process of configuring the applicationContext.xml file, the main work is to configure bean-related information. These beans are created in advance, but in fact the so-called beans are objects;
The purpose of handing over the creation of objects to the spring container is to decouple;
In addition, when using struts, spring registers action as bean, which is a singleton by default. Not every time a new action is released during access, there will be risks when concurrent access;
However, you can configure the action into multiple cases through scope="prototype"; ps: The action in struts2 is multi-case by default;
Note: The beans configured in applicationContext.xml and the beans configured in custom annotations can be obtained directly during the program's running. This is easy to verify, just write a small program;
6. Understand spring aop (section-oriented programming), and write custom section functions to verify the results
This idea is used in many places in this form of sectional programming, such as filters, interceptors, transaction control, etc.
The principle is Java reflection and dynamic proxy, which controls the method before and after execution, and adds the code you want to execute;
A section is added to the small example, and before and after strings are printed before and after the method is executed. As shown in the figure below, it works normally. Please refer to the previous part of the code:
<!-- Custom aop processing test--> <bean id="aopTest"></bean> <bean id="myAop"></bean> <aop:config proxy-target-class="true"> <aop:aspect ref="myAop"> <aop:pointcut id="pcMethodTest" expression="execution(* ssh.aop.AopTest.test*(..))"/> <aop:before pointcut-ref="pcMethodTest" method="before"/> <aop:after pointcut-ref="pcMethodTest" method="after"/> </aop:aspect> </aop:config>
@author A wind-like coder
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.