摘要
最近一直在折騰java web相關內容,這里就把最近學習的spring+struts2+hibernate進行一個整合,也就是大家經常說的ssh。
環境
工具IDE :Idea 2018
數據庫:Mysql
關於如何安裝tomcat、mysql、idea,請自行查找。
1、使用idea創建spring項目
2、創建項目SSHDemo,項目結構如下
3、添加三層的包。
這里采用三層的架構進行項目的設計
action存放struts2的action類
dao 數據庫操作
service業務層
test單元測試
domain javabean
4、配置struts2
在web.xml中你會看到下面的紅字提示,引起這個的原因是因為struts2 版本>=2.5 需要使用另外的方式進行配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <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>/*</url-pattern> </filter-mapping> </web-app>
修改后的配置如下
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter>
其他內容不變
在action包 添加一個UserAction
package com.ssh.action; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; import com.ssh.domain.User; /** * user相關action */ public class UserAction extends ActionSupport implements ModelDriven<User> { private User user = new User(); @Override public User getModel() { return user; } public String login() { System.out.println(user); return NONE; } }
配置struts.xml
<struts> <package name="user" extends="struts-default" namespace="/"> <action name="user_*" class="com.ssh.action.UserAction" method="{1}"/> </package> </struts>
添加一個登錄頁面login.jsp測試
<%-- Created by IntelliJ IDEA. User: sunwy Date: 2018/6/6 Time: 10:23 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登錄</title> </head> <body> <form action="${pageContext.request.contextPath}/user_login.action"> 用戶名:<input type="text" name="name"> 密碼:<input type="password" name="password" id="password"> <input type="submit" value="登錄"> </form> </body> </html>
啟動
在啟動時發現如下內容
嚴重: Context [] startup failed due to previous errors
[2018-06-06 10:25:36,908] Artifact SSHDemo:war exploded: Error during artifact deployment. See server log for details.
打開project structure修復出現的問題
重啟Tomcat發現如下錯誤
六月 06, 2018 10:57:12 上午 org.apache.catalina.startup.TldConfig execute
信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
ERROR StatusLogger Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
ERROR Dispatcher Dispatcher initialization failed
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:289)
at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.construct(ContainerImpl.java:422)
at com.opensymphony.xwork2.inject.ContainerBuilder$5.create(ContainerBuilder.java:231)
at com.opensymphony.xwork2.inject.Scope$2$1.create(Scope.java:52)
at com.opensymphony.xwork2.inject.ContainerBuilder$3.create(ContainerBuilder.java:106)
at com.opensymphony.xwork2.inject.ContainerBuilder$7.call(ContainerBuilder.java:584)
at com.opensymphony.xwork2.inject.ContainerBuilder$7.call(ContainerBuilder.java:581)
at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:560)
at com.opensymphony.xwork2.inject.ContainerBuilder.create(ContainerBuilder.java:581)
at com.opensymphony.xwork2.config.impl.DefaultConfiguration.createBootstrapContainer(DefaultConfiguration.java:287)
at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:162)
at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:66)
at org.apache.struts2.dispatcher.Dispatcher.getContainer(Dispatcher.java:957)
at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:463)
at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:496)
at org.apache.struts2.dispatcher.InitOperations.initDispatcher(InitOperations.java:73)
at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:61)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:285)
at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:266)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:108)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4997)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5699)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1017)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:993)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1900)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:618)
at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:565)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401)
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:835)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:287)
... 64 more
Caused by: java.lang.ExceptionInInitializerError
at com.opensymphony.xwork2.ognl.OgnlValueStackFactory.setContainer(OgnlValueStackFactory.java:88)
... 69 more
Caused by: java.lang.IllegalArgumentException: Javassist library is missing in classpath! Please add missed dependency!
at ognl.OgnlRuntime.<clinit>(OgnlRuntime.java:169)
... 70 more
Caused by: java.lang.ClassNotFoundException: javassist.ClassPool
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1928)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1771)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at ognl.OgnlRuntime.<clinit>(OgnlRuntime.java:166)
... 70 more
六月 06, 2018 10:57:12 上午 org.apache.catalina.core.StandardContext startInternal
嚴重: One or more Filters failed to start. Full details will be found in the appropriate container log file
六月 06, 2018 10:57:12 上午 org.apache.catalina.core.StandardContext startInternal
嚴重: Context [] startup failed due to previous errors
好吧,解決問題吧
Caused by: java.lang.ClassNotFoundException: javassist.ClassPool
這個問題,是由於沒有引入javassist-3.11.0.GA.jar包引起的,那么找到該包,引入即可
重新發布,輸入用戶名和密碼
HTTP Status 404 - There is no Action mapped for namespace [/] and action name [user_find] associated with context path [].
注意
在struts2.3之前的版本,正常的配置就可以了,但在struts2.3版本之后,使用通配符調用方法時,內部會驗證是否允許訪問該方法,所以要加上
<allowed-methods>方法名1,方法名2…</allowed-methods>代碼。
參考:https://www.cnblogs.com/gsy52300/p/5778754.html
最后struts.xml文件內容,這種配置也是一種安全設置,通配符,如果該action有其他不想被別人訪問到的方法,如果通過通配符的方式,直接暴漏出來了,通過這種配置,可以配置允許訪問哪些方法,對其它隱私的方法進行保護。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <package name="userAction" extends="struts-default" namespace="/"> <action name="user_*" method="{1}" class="com.ssh.action.UserAction"> <allowed-methods>login</allowed-methods> </action> </package> </struts>
測試struts2
后台action能收到數據
好了,到這里,struts2 算是配置成功了,發現還是不容易的。
整合spring
在src目錄下添加applicationContext.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--將action的創建交給spring ioc 注意action是多例的 一定要將scope設置為prototype--> <bean class="com.ssh.action.UserAction" id="userAction" scope="prototype"/> </beans>
我們希望在服務器啟動的時候加載該配置文件,那么需要在web.xml添加如下內容
<!--配置spring在啟動服務器的是加載配置文件的監聽器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!--配置具體的配置文件的位置--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param>
這里需要添加spring-web-3.2.0.RELEASE.jar包
成功加載
整合Hibernate
添加jar包
在src目錄下添加hibernate配置文件hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!--配置sessionFactory--> <session-factory> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql:///sshdemo</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">abcd</property> <!--配置數據庫方言--> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!--可選配置--> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <!--是否根據javabean自動生成表結構--> <property name="hibernate.hbm2ddl.auto">update</property> <!--連接池--> <!--提供商--> <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> <!--連接池中最小的可用連接--> <property name="c3p0.min_size">5</property> <!--最大連接--> <property name="c3p0.max_size">20</property> <!--數據庫連接的過期時間 秒 如果數據庫連接池中的某個連接處於空閑時間超過了timeout,則從連接池中清除--> <property name="c3p0.timeout">120</property> <!--每3000s檢查空間連接--> <property name="c3p0.idle_test_period">3000</property
<!--配置映射-->
<mapping resource="com/ssh/domain/User.hbm.xml"/>
</session-factory> </hibernate-configuration>
在domain包下添加映射配置User.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.ssh.domain.User" table="users"> <id name="id" column="id"> <generator class="native"></generator> </id> <property name="name" column="name"></property> <property name="password" column="password"></property> </class> </hibernate-mapping>
在applicationContext.xml中添加如下配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 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.xsd"> <!--加載sessionFactory配置--> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="classpath:hibernate.cfg.xml"></property> </bean> <!-- 注入事務管理器,提交事務和回滾事務 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <!--開啟事務注解方式--> <tx:annotation-driven transaction-manager="transactionManager"/> <!--配置userDao--> <bean class="com.ssh.dao.UserDao" id="userDao"> <!--注入sessionFactory--> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!--配置userService--> <bean id="userService" class="com.ssh.service.UserService"> <!--注入userDao--> <property name="userDao" ref="userDao"></property> </bean> <!--將action的創建交給spring ioc 注意action是多例的 一定要將scope設置為prototype--> <bean class="com.ssh.action.UserAction" id="userAction" scope="prototype"/> </beans>
userDao
package com.ssh.dao; import com.ssh.domain.User; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; public class UserDao extends HibernateDaoSupport { public void save(User user) { this.getHibernateTemplate().save(user); } }
userService
package com.ssh.service; import com.ssh.dao.UserDao; import com.ssh.domain.User; import org.springframework.transaction.annotation.Transactional; @Transactional public class UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void save(User user) { userDao.save(user); } }
userServiceTest
package com.ssh.test; import com.ssh.domain.User; import com.ssh.service.UserService; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.annotation.Resource; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class UserServiceTest { @Resource(name = "userService") private UserService userService; @Test public void saveTest() { User user = new User(); user.setId(1); user.setName("wolfy"); user.setPassword("1234"); userService.save(user); } }
測試
總結
1、配置過程很麻煩,很可能會缺包。
2、在保存數據的時候發現,執行了,但數據庫中沒有數據,原因是因為沒有配置事務管理器,還要注意開啟注解的方式管理事務。
3、當然仍然可以進一步的整合,比如去掉hibernate.cfg.xml文件,在applicationContext.xml進行配置
4、注意如果使用hibernate4需要下載hibernate4.2+的jar包