SSH框架:Struts2-2.3.7+Spring4.2+Hibernate5.4

完整MyEclipse搭建SSH框架,教程+源码

完整工程下载地址:SSH

准备工作,jar包

  1. Struts2下载官网点这里
    最新版本为2.5,这里用2.3

在这里插入图片描述

  1. Spring下载官网点这里
    根据自己版本选择下载:
    具体教程可见另一篇:https://blog.csdn.net/weixin_42176639/article/details/94360648
    在这里插入图片描述在这里插入图片描述

  2. Hibernatehibernate官网
    在这里插入图片描述在这里插入图片描述4. 搭建SSH所需的jar包 ,图中文件包括数据库驱动包,druid数据库连接池,ajax包:
    在这里插入图片描述在这里插入图片描述在这里插入图片描述
    5.工程目录结构
    在这里插入图片描述
    在这里插入图片描述

6.配置文件说明

  • 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:p="http://www.springframework.org/schema/p"  
        xmlns:aop="http://www.springframework.org/schema/aop"   
        xmlns:context="http://www.springframework.org/schema/context"  
        xmlns:jee="http://www.springframework.org/schema/jee"  
        xmlns:tx="http://www.springframework.org/schema/tx"  
        xsi:schemaLocation="    
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
    <!-- 类似于财务部门一样,类就是钱,所有需要类的实例都由srping去管理 -->
    <!-- 配置注解自动扫描的包 -->  
   	<!-- <context:component-scan base-package="com.ssh.*"></context:component-scan> -->
	
	<!-- 配置数据源 -->  
   	<context:property-placeholder location="classpath:druid_db.properties"/>  
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
	    
	    <!-- c3p0 -->
	    <!-- <property name="driverClass" value="${jdbc.driverClass}"/> -->
		<!-- <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/> -->
		<!-- <property name="user" value="${jdbc.user}"/> -->
		<property name="driverClassName" value="${jdbc.driverClass}"/>
		<property name="url" value="${jdbc.jdbcUrl}"/>
		<property name="username" value="${jdbc.user}"/>
		<property name="password" value="${jdbc.password}"/>
		<!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 ,log4j--> 
		<property name="filters" value="stat" />	
		
		<!-- 配置初始化大小、最小、最大 --> 
		<property name="initialSize" value="2" /> 
		<property name="minIdle" value="1" /> 
		<property name="maxActive" value="20" />
		
		<!-- 配置获取连接等待超时的时间 ms 60s--> 
		<property name="maxWait" value="60000" />
		
		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> 
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> 
		<property name="minEvictableIdleTimeMillis" value="300000" />
		<!-- oracle必须这样配置检查,不了会报检查错误 -->
        <!-- <property name="validationQuery" value="SELECT 1 FROM DUAL" /> -->
		<property name="validationQuery" value="select 1" /> 
		<property name="testWhileIdle" value="true" /> 
		<property name="testOnBorrow" value="false" /> 
		<property name="testOnReturn" value="false" />
		
		<!-- 打开 removeAbandoned 功能 -->  
        <property name = "removeAbandoned" value = "true" />  
        <!-- 1800 秒,也就是 30 分钟 -->  
        <property name = "removeAbandonedTimeout" value ="1800" /> 
		
		<!-- 打开PSCache,并且指定每个连接上PSCache的大小 --> 
		<!-- 如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。分库分表较多的数据库,建议配置为false。 --> 
		<property name="poolPreparedStatements" value="false" /> 
		<property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
		
		<property name="keepAlive" value="true" />
		
	</bean>
	<!-- 生成SessionFactory -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" scope="prototype">
    
		<!-- 使用某个数据源生成SessionFactory -->
		<property name="dataSource" ref="dataSource"></property>
		<!-- hibernate 配置文件的路径 -->  
		<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
		<!-- <property name="hibernateProperties">  
	        <props>
	          <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate5.SpringSessionContext</prop>
	        </props>
	    </property>
	 	-->
    </bean>
    <!-- 配置事务管理器 -->
	<bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" ></property>
	</bean>
	
	<!-- 配置dao -->
	<!-- 配置service -->
	<!-- 配置action -->
	
	<!-- 登录 -->
	<bean id="log_d" class="com.demo.daoImpl.LogDaoImpl">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	<bean id="log_s" class="com.demo.serviceImpl.LogServiceImpl">
		<property name="dao" ref="log_d"></property>
	</bean>
	<bean id="log_a" class="com.demo.action.LogAction" scope="prototype">
		<property name="service" ref="log_s"></property>
	</bean>
	
	
	<!-- 用户 tb_user -->
	<bean id="user_d" class="com.demo.daoImpl.UserDaoImpl">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	<bean id="user_s" class="com.demo.serviceImpl.UserServiceImpl">
		<property name="dao" ref="user_d"></property>
	</bean>
	<bean id="user_a" class="com.demo.action.UserAction" scope="prototype">
		<property name="service" ref="user_s"></property>
	</bean>
	
    <!-- 基于注解的事务,当注解中发现@Transactional时,使用id为“transactionManager”的事务管理器 -->
    <!-- 如果没有设置transaction-manager的值,则spring以缺省默认的事务管理器来处理事务,默认事务管理器为第一个加载的事务管理器 -->
    <!-- <tx:annotation-driven transaction-manager="transactionManager"/> -->
    <tx:annotation-driven />	
	<!-- 声明式容器事务管理 ,transaction-manager指定事务管理器为transactionManager -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">

        <tx:attributes>
            <tx:method name="find*" read-only="true" />
            <tx:method name="get*"  read-only="true" />
            <tx:method name="add*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="test*" propagation="REQUIRED" />
            <tx:method name="*Transaction" propagation="REQUIRED" />
            <tx:method name="*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>
    <!-- 只对业务逻辑层实施事务 -->
    <aop:config expose-proxy="true"> 
        <aop:pointcut expression="execution(* com.demo.serviceImpl.*.*(..))" id="txPointcut"/>
        <!-- Advisor定义,切入点和通知分别为txPointcut、txAdvice -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut" />
    </aop:config>

</beans>
  • 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>
	<session-factory>
		<!-- 数据库连接配 置 默认的-->
		<!-- 在建立sessionfactory时会引入hibernate.cfg.xml,需要用到数据库配置信息 -->
		<property name="connection.driver_class">
			com.microsoft.sqlserver.jdbc.SQLServerDriver
		</property>
		<property name="connection.url">
			jdbc:sqlserver://127.0.0.1:1433;DatabaseName=Test_SSH
		</property>
		<property name="connection.username">sa</property>
		<property name="connection.password">654321</property>
		<property name="connection.characterEncoding">UTF-8</property>
		<!-- 在hibernate里配置druid的连接信息 -->
		<!-- <property name="hibernate.connection.provider_class">com.alibaba.druid.support.hibernate.DruidConnectionProvider</property>
			<property name="driverClassName">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
			<property name="url">jdbc:sqlserver://127.0.0.1:1433;DatabaseName=Test_SSH</property>
			<property name="username">sa</property>
			<property name="password">654321</property>
		-->



		<property name="hibernate.current_session_context_class">
			org.springframework.orm.hibernate5.SpringSessionContext
		</property>
		<!-- 每个数据库都有1个,针对特定的关系型数据库生成优化的SQL -->
		<!-- 会报错找不到:org.hibernate.dialect.SQLServer2008Dialect -->
		<property name="dialect">
			org.hibernate.dialect.SQLServerDialect
		</property>

		<!-- 显示SQL -->
		<property name="show_sql">false</property>
		<!-- 格式化SQL -->
		<property name="format_sql">true</property>
		<!-- 根据schema更新数据表的工具 -->
		<property name="hbm2ddl.auto">update</property>


		<!-- #hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider -->
		<!-- <property name="hibernate.connection.provider_class">
			org.hibernate.connection.C3P0ConnectionProvider
			
			</property>
		-->

		<!-- 数据表映射配置文件 -->
		<mapping resource="com/demo/entity/TbUsers.hbm.xml" />

	</session-factory>
</hibernate-configuration>
  • struts.xml
<?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">
<!-- 上面的头,注意版本,从样例里复制过来 showcase.war\WEB-INF\src\java\struts.xml -->
<struts>
	<!-- 告知Struts2运行时使用Spring来创建对象 -->

	<constant value="utf-8" name="struts.i18n.encoding" />
	<constant value="Massage" name="struts.custom.i18n.resources" />
	<constant value="/chatext,/pages/mes/TakePhoto.html" name="struts.action.excludePattern" />
	<constant value="gif,jpeg,jpg,png,bmp" name="com.chinacnd.allowed.images" />

	<constant name="struts.enable.DynamicMethodInvocation" value="true" />
	<constant name="struts.devMode" value="false" /><!-- true开发模式 -->
	<constant name="struts.objectFactory" value="spring" />
	<constant name="struts.multipart.saveDir" value="E://mesPhotos"></constant><!-- 临时文件夹 -->
	<constant name="struts.multipart.maxSize" value="10701096" /><!-- 最大上传10M -->

	<!-- 第1步:先定义一个包 -->
	<package name="demo" extends="struts-default" namespace="/">
		<!-- 第2步:定义一个action,配置跳转信息 name 类似于Servlet @WebServlet("/IndexServlet")
		http://xxxx/xxx/Index.action http://xxxx/xxx/Index class
		对应于自己写的Action类 当不写method属性时,默认调用的是execute
		class="ssh.action.IndexAction" ** new ssh.action.IndexAction()
		设计思想:关心了具体的实现类必须改为不要关注那个实现类
		加入spring后,struts的action节点的class属性意义发生变化,直接引用spring帮忙创建的实例 -->
		<action name="UserExist" class="user_a" method="IfExist">
			<result name="success">index.jsp</result>
			<result name="error">indexs.jsp</result>
		</action>

	</package>
	<!-- extends="json-default" 阿贾克斯-->
    <package name="ajax" namespace="/ajax" extends="json-default"> 
		<action name="LogIn" class="log_a" method="LogIn">
   			<result type="json"></result>
   		</action>
	
	</package>
	
</struts>
  • druid.properties
jdbc.driverClass=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.jdbcUrl=jdbc:sqlserver://127.0.0.1:1433;DatabaseName=Test_SSH
jdbc.user=sa
jdbc.password=******
  • logback-test.xml --日志记录配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->  
<!-- 日志输出规则  根据当前ROOT 级别,日志输出时,级别高于root默认的级别时  会输出 -->  
<!-- 以下  每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志-->

<!-- 属性描述 scan:性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。   
     debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->  
<configuration debug="false" scan="true" scanPeriod="60 seconds">
 	
 	<!-- Stop output INFO at start -->
    <statusListener class="ch.qos.logback.core.status.NopStatusListener" />
 	
 	<property name="LogBack_WARN" value="C:/Log/My_SSH/logback_warn"></property> //这里为日志的存储地址
	<property name="LogBack_ERROR" value="C:/Log/My_SSH/logback_error"></property> //这里为日志的存储地址
	<property name="LogBack_INFO" value="C:/Log/My_SSH/logback_info"></property> //这里为日志的存储地址
	<property name="LogBack_DEBUG" value="C:/Log/My_SSH/logback_debug"></property> //这里为日志的存储地址
	
	
	<!-- 日志最大的历史 30天 -->  
    <property name="maxHistory_WARN" value="60"/>  
	<property name="maxHistory_ERROR" value="60"/>  
	<property name="maxHistory_INFO" value="30"/> 
	<property name="maxHistory_DEBUG" value="60"/> 
    <!-- 负责写日志,控制台日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- 一是把日志信息转换成字节数组,二是把字节数组写入到输出流 -->
        <encoder>
            <Pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%5level] [%thread] %logger{0} %msg%n</Pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
 
 	<!-- WARN级别日志 appender -->  
    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <!-- 过滤器,只记录WARN级别的日志 -->  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>WARN</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!-- 按天回滚 daily -->  
            <fileNamePattern>${LogBack_WARN}/%d{yyyy-MM-dd}/warn-log.log</fileNamePattern>  
            <!-- 日志最大的历史 60天 -->  
            <maxHistory>${maxHistory_WARN}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender>
 	
 	<!-- ERROR级别日志 -->  
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender-->  
    <appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">  
		<!-- 过滤器,只记录WARN级别的日志 -->  
		<filter class="ch.qos.logback.classic.filter.LevelFilter">  
			<level>ERROR</level>  
			<onMatch>ACCEPT</onMatch>  
			<onMismatch>DENY</onMismatch>  
		</filter>  
        <!-- 最常用的滚动策略,它根据时间来制定滚动策略.既负责滚动也负责出发滚动 -->  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!--日志输出位置  可相对、和绝对路径 -->  
            <fileNamePattern>${LogBack_ERROR}/%d{yyyy-MM-dd}/error-log.log</fileNamePattern>  
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6,  
           	 则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除-->  
            <maxHistory>${maxHistory_ERROR}</maxHistory>  
        </rollingPolicy>  
          
        <!-- 按照固定窗口模式生成日志文件,当文件大于20MB时,生成新的日志文件。窗口大小是1到3,当保存了3个归档文件后,将覆盖最早的日志。   
        <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">     
          <fileNamePattern>${log_dir}/%d{yyyy-MM-dd}/.log.zip</fileNamePattern>     
          <minIndex>1</minIndex>     
          <maxIndex>3</maxIndex>     
        </rollingPolicy>   -->  
        <!-- 查看当前活动文件的大小,如果超过指定大小会告知RollingFileAppender 触发当前活动文件滚动   
        <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">     
            <maxFileSize>5MB</maxFileSize>     
        </triggeringPolicy>   -->  
          
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender> 
 
    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
    <!-- 按日期和大小区分的滚动日志 -->
	<appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
    	
		<filter class="ch.qos.logback.classic.filter.LevelFilter">
			<level>INFO</level>
			<onMatch>ACCEPT</onMatch>
			<onMismatch>DENY</onMismatch>
		</filter>
		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
			<fileNamePattern>${LogBack_INFO}/%d{yyyy-MM-dd}/info-log.log</fileNamePattern>
			<maxHistory>${maxHistory_INFO}</maxHistory>
 			
		</rollingPolicy>
		<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
			<maxFileSize>10MB</maxFileSize>
		</timeBasedFileNamingAndTriggeringPolicy>
		<encoder>
			<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{85} - %msg%n</Pattern>
		</encoder>
	</appender>
	
	<!-- 文件日志 -->
    <appender name="DEBUG" class="ch.qos.logback.core.FileAppender">
        
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <!-- LevelFilter: 级别过滤器,根据日志级别进行过滤 -->
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <!-- 按天回滚 daily -->  
            <fileNamePattern>${LogBack_DEBUG}/%d{yyyy-MM-dd}/debug-log.log</fileNamePattern>  
            <!-- 日志最大的历史 60天 -->  
            <maxHistory>${maxHistory_DEBUG}</maxHistory>  
        </rollingPolicy> 
        <encoder>
            <Pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%5level] [%thread] %logger{0} %msg%n</Pattern>
            <charset>UTF-8</charset>
        </encoder>
    </appender>
 
 	<!-- TRACE级别日志 appender -->  
    <!-- <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        	过滤器,只记录ERROR级别的日志  
        <filter class="ch.qos.logback.classic.filter.LevelFilter">  
            <level>TRACE</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
        </filter>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            	按天回滚 daily  
            <fileNamePattern>${LogBack_ERROR}/%d{yyyy-MM-dd}/trace-log.log  
            </fileNamePattern>  
           	 日志最大的历史 60天  
            <maxHistory>${maxHistory_ERROR}</maxHistory>  
        </rollingPolicy>  
        <encoder>  
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>  
        </encoder>  
    </appender> -->  
 	
	<!--<!– 异常日志输出 –>-->
    <!--<appender name="EXCEPTION" class="ch.qos.logback.core.rolling.RollingFileAppender">-->
        <!--<file>exception.log</file>-->
        <!--<!– 求值过滤器,评估、鉴别日志是否符合指定条件. 需要额外的两个JAR包,commons-compiler.jar和janino.jar –>-->
        <!--<filter class="ch.qos.logback.core.filter.EvaluatorFilter">-->
            <!--<!– 默认为 ch.qos.logback.classic.boolex.JaninoEventEvaluator –>-->
            <!--<evaluator>-->
                <!--<!– 过滤掉所有日志消息中不包含"Exception"字符串的日志 –>-->
                <!--<expression>return message.contains("Exception");</expression>-->
            <!--</evaluator>-->
            <!--<OnMatch>ACCEPT</OnMatch>-->
            <!--<OnMismatch>DENY</OnMismatch>-->
        <!--</filter>-->
 
        <!--<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">-->
            <!--<!– 触发节点,按固定文件大小生成,超过5M,生成新的日志文件 –>-->
            <!--<maxFileSize>5MB</maxFileSize>-->
        <!--</triggeringPolicy>-->
    <!--</appender>-->
 	
    
 
    <!-- 异步输出 -->
    <appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">
        <!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold >0</discardingThreshold>
        <!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>512</queueSize>
        <!-- 添加附加的appender,最多只能添加一个 -->
        <appender-ref ref ="ERROR"/>
    </appender>
 
    <!--
    - 1.name:包名或类名,用来指定受此logger约束的某一个包或者具体的某一个类
    - 2.未设置打印级别,所以继承他的上级<root>的日志级别“DEBUG”
    - 3.未设置additivity,默认为true,将此logger的打印信息向上级传递;
    - 4.未设置appender,此logger本身不打印任何信息,级别为“DEBUG”及大于“DEBUG”的日志信息传递给root,
    -  root接到下级传递的信息,交给已经配置好的名为“STDOUT”的appender处理,“STDOUT”appender将信息打印到控制台;
    -->
    <logger name="ch.qos.logback" />
 	<!-- show parameters for hibernate sql 专为 Hibernate 定制 -->  
    <logger name="org.hibernate.type.descriptor.sql.BasicBinder"  level="TRACE" />  
    <logger name="org.hibernate.type.descriptor.sql.BasicExtractor"  level="DEBUG" />  
    <logger name="org.hibernate.SQL" level="DEBUG" />
    <logger name="org.hibernate.type" level="TRACE" />
    <logger name="org.hibernate.engine.QueryParameters" level="DEBUG" />  
    <logger name="org.hibernate.engine.query.HQLQueryPlan" level="DEBUG" /> 
    <!--
    - 1.将级别为“INFO”及大于“INFO”的日志信息交给此logger指定的名为“STDOUT”的appender处理,在控制台中打出日志,
    -   不再向次logger的上级 <logger name="logback"/> 传递打印信息
    - 2.level:设置打印级别(TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF),还有一个特殊值INHERITED或者同义词NULL,代表强制执行上级的级别。
    -        如果未设置此属性,那么当前logger将会继承上级的级别。
    - 3.additivity:为false,表示此logger的打印信息不再向上级传递,如果设置为true,会打印两次
    - 4.appender-ref:指定了名字为"STDOUT"的appender。
    -->
    <logger name="com.demo.z_Test.LogBack_Test" level="WARN" additivity="false">
        <!-- <appender-ref ref="STDOUT"/> -->
        <appender-ref ref="WARN"/>
        <appender-ref ref="ERROR"/>
        <!-- <appender-ref ref="INFO"/> -->
        <!--<appender-ref ref="DEBUG"/>-->
        <!--<appender-ref ref="EXCEPTION"/>-->
        
        <!-- <appender-ref ref="ASYNC"/> -->
    </logger>
 
    <!--
    - 根logger
    - level:设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,不能设置为INHERITED或者同义词NULL。
    -       默认是DEBUG。
    -appender-ref:可以包含零个或多个<appender-ref>元素,标识这个appender将会添加到这个logger
    -->
    <root level="WARN">
        <!-- <appender-ref ref="STDOUT"/> -->
        <appender-ref ref="WARN"/>
        <appender-ref ref="ERROR"/>
        <!-- <appender-ref ref="INFO"/> -->
        <!--<appender-ref ref="DEBUG"/>-->
        <!--<appender-ref ref="EXCEPTION"/>-->
        <!-- <appender-ref ref="ASYNC"/> -->
    </root>
</configuration>
  • web.xml:此处配置了自定义的拦截器和session监听器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>MySSH</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  	<context-param>
	    <param-name>webAppRootKey</param-name>
	    <param-value>WEB.ROOT</param-value>
  	</context-param>
  	<!-- spring的监听器配置开始 -->
    <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>
  	<listener>
    	<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  	</listener>
  	<listener>
		<listener-class>com.demo.dbutil.SessionListener</listener-class>
  	</listener>
    <!-- <servlet>  
        <servlet-name>DruidStatView</servlet-name>  
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>  
	</servlet>  
	<servlet-mapping>  
	        <servlet-name>DruidStatView</servlet-name>  
	        <url-pattern>/druid/*</url-pattern>  
	</servlet-mapping>
	   -->
	<!-- 用户登录验证过滤器 -->
    <filter>
        <filter-name>UserLogFilter</filter-name>
        <filter-class>com.demo.Filter.UserLogFilter</filter-class>
    </filter>
	<filter-mapping>
        <filter-name>UserLogFilter</filter-name>
        <url-pattern>/pages/*</url-pattern>
    </filter-mapping>   
    <!-- struts2的过滤器 -->
    <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>
    <!-- hibernate session过滤器 -->
    <filter>
    <filter-name>openSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
	</filter>
	<filter-mapping>
	   <filter-name>openSessionInViewFilter</filter-name>
	   <url-pattern>/*</url-pattern>
	</filter-mapping>
    
    
    
</web-app>

工程文件

HibernateUtil.java:sessionFactory的实现

package com.demo.hibernate;
 
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
 
public class HibernateUtil {
	//为保证线程安全,将Seeeion放到ThreadLocal中管理。这样就避免了Session的多线程共享数据的问题
	private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private static SessionFactory sessionFactory = null;//SessionFactory对象
    //静态块(在类被加载时执行,且生命周期内只执行一次)
	static {
    	try {
    		// 加载Hibernate配置文件,默认为hibernate.cfg.xml
			Configuration cfg = new Configuration().configure();
			//	创建会话工厂
			//	hibernate4.0版本前这样获取sessionFactory = configuration.buildSessionFactory();
			//	hibernate5以后规定,所有的配置或服务,要生效,必须配置或服务注册到一个服务注册类(服务构建器-->服务注册器)
			ServiceRegistry serviceRegistry = cfg.getStandardServiceRegistryBuilder().build();
			//  根据服务注册类创建一个元数据资源集,同时构建元数据并生成应用一般唯一的的session工厂
			sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
		} catch (Exception e) {
			System.err.println("1:创建会话工厂失败");
			e.printStackTrace();
		}
    }
	/**
     *	获取Session
     *  @return Session
     *  @throws HibernateException
     */
    public static Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();	//获取ThreadLocal中当前线程共享变量的值。
		if (session == null || !session.isOpen()) {
			if (sessionFactory == null) {		//如果会话工厂创建失败为空就在重新创建一次
				rebuildSessionFactory();
			}
			//创建Sqlsession数据库会话
			session = (sessionFactory != null) ? sessionFactory.openSession(): null;
			//设置ThreadLocal中当前线程共享变量的值。
			threadLocal.set(session);
		}
 
        return session;
    }
	/**
     * 重建会话工厂
     */
	public static void rebuildSessionFactory() {
    	try {
    		// 加载Hibernate配置文件
			Configuration cfg = new Configuration().configure();
			//	创建会话工厂
			//	hibernate4.0版本前这样获取sessionFactory = configuration.buildSessionFactory();
			//	hibernate5以后规定,所有的配置或服务,要生效,必须配置或服务注册到一个服务注册类(服务构建器-->服务注册器)
			ServiceRegistry serviceRegistry = cfg.getStandardServiceRegistryBuilder().build();
			//  根据服务注册类创建一个元数据资源集,同时构建元数据并生成应用一般唯一的的session工厂
			sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
		} catch (Exception e) {
			System.err.println("2:创建会话工厂失败");
			e.printStackTrace();
		}
	}
	/**
	 * 获取SessionFactory对象
	 * @return SessionFactory对象
	 */
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	/** 
     *	关闭Session
     *  @throws HibernateException
     */
    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        //使用set(null)来回收ThreadLocal设置的值.
        threadLocal.set(null);
        if (session != null) {
            session.close();//关闭Session
        }
    }
}

SessionListener监听器

package com.demo.dbutil;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;


public class SessionListener implements HttpSessionListener{

	private MySessionContext myc = MySessionContext.getInstance();
	public void sessionCreated(HttpSessionEvent httpSessionEvent) {
		HttpSession session = httpSessionEvent.getSession();
		myc.addSession(session);
		//System.out.println("获取session:"+session.getId());
		
	}
	public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
		HttpSession session = httpSessionEvent.getSession();
		myc.delSession(session);
		//System.out.println("丢失session:"+session.getId());
		//session过期时要恢复用户登录状态
		
	}
	
	
}

MySessionContext

package com.demo.dbutil;

import java.util.HashMap;

import javax.servlet.http.HttpSession;

public class MySessionContext {
	
	private static MySessionContext instance;  
    private HashMap<String,HttpSession> sessionMap;  

    private MySessionContext() {  
        sessionMap = new HashMap<String,HttpSession>();  
    }  

    public static MySessionContext getInstance() {  
        if (instance == null) {  
            instance = new MySessionContext();  
        }  
        return instance;  
    }  

    public synchronized void addSession(HttpSession session) {  
        if (session != null) {  
            sessionMap.put(session.getId(), session);  
        }  
    }  

    public synchronized void delSession(HttpSession session) {  
        if (session != null) {  
            sessionMap.remove(session.getId());  
        }  
    }  

    public synchronized HttpSession getSession(String sessionID) {  
        if (sessionID == null) {  
            return null;  
        }  
        return sessionMap.get(sessionID);  
    }  



}

DAO层的实现
daoImpl

package com.demo.daoImpl;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import com.demo.dao.LogDao;
import com.demo.entity.TbUsers;
import com.demo.hibernate.HibernateUtil;

public class LogDaoImpl extends HibernateDaoSupport implements LogDao{
	
	/*
	 * 登录
	 */
	@SuppressWarnings("unchecked")
	public List<TbUsers> Login(String account,String password){
		
		Session session = null;
		List<TbUsers> list = null;
		session = HibernateUtil.getSession(); 
		// HQL查询的是实体类的名称,不是数据表的名称 
		String hql = "from TbUsers u where u.userAccount=?0 and u.userPassword=?1";
		if(session!=null){
			try{
				Query<TbUsers> query = session.createQuery(hql); 
				query.setParameter(0, account);
				query.setParameter(1, password);
				list = query.list();
			}catch(HibernateException e){
				e.printStackTrace();
			}
			
			
		}
		HibernateUtil.closeSession();
		return list;
		
	}
	
	/*
	 * 改变登录状态
	 */
	@SuppressWarnings("rawtypes")
	public boolean UpdateUserState(String sessionId,String state,String account,String password){
		boolean ret = true;
		Session session = null;
		Transaction tx = null;
		session = HibernateUtil.getSession();
		String hql = "update TbUsers u set u.userC = ?0, u.userD = ?1 "
					+"where u.userAccount = ?2 and u.userPassword = ?3"; //第二种删除方式
		if(session!=null){
			try{
				tx = session.beginTransaction();
				Query query = session.createQuery(hql);
				query.setParameter(0,sessionId);
				query.setParameter(1,state);
				query.setParameter(2,account);
				query.setParameter(3,password);
				query.executeUpdate();
				tx.commit();
			}catch(HibernateException e){
				ret = false;
				e.printStackTrace();
				tx.rollback();
			}
		}
		
		HibernateUtil.closeSession();
		return ret;
	}
	
	/*
	 * session销毁时清空状态信息
	 */

	@SuppressWarnings("rawtypes")
	public boolean UpdateUserStateBySession(String sessionId){
		//System.out.println("更新session:"+sessionId);
		boolean ret = true;
		Session session = null;
		Transaction tx = null;
		session = HibernateUtil.getSession();
		String hql = "update TbUsers u set u.userC=?0 u.userD = ?1"
					+"where u.userC = ?2"; //第二种删除方式
		if(session!=null){
			try{
				tx = session.beginTransaction();
				Query query = session.createQuery(hql);
				query.setParameter(0,"");
				query.setParameter(1,"0");
				query.setParameter(2,sessionId);
				query.executeUpdate();
				tx.commit();
			}catch(HibernateException e){
				ret = false;
				e.printStackTrace();
				tx.rollback();
			}
		}
		
		HibernateUtil.closeSession();
		return ret;
	}

	
}

dao

package com.demo.dao;

import java.util.List;

import com.demo.entity.TbUsers;

public interface LogDao {

	public List<TbUsers> Login(String account,String password);
	public boolean UpdateUserState(String sessionId,String state,String account,String password);
	public boolean UpdateUserStateBySession(String sessionId);
}

SERVICE层
serviceImpl

package com.demo.serviceImpl;

import java.util.List;

import com.demo.dao.LogDao;
import com.demo.entity.TbUsers;
import com.demo.service.LogService;

public class LogServiceImpl implements LogService{

	private LogDao dao;
	public void setDao(LogDao dao) {
		this.dao = dao;
	}

	@Override
	public List<TbUsers> Login(String account, String password) {
		// TODO Auto-generated method stub
		return dao.Login(account, password);
	}
	
	public boolean UpdateUserState(String sessionId,String state,String account,String password){
		return dao.UpdateUserState(sessionId,state, account, password);
	}
	
	public boolean UpdateUserStateBySession(String sessionId){
		return dao.UpdateUserStateBySession(sessionId);
	}
	
}

service

package com.demo.service;

import java.util.List;

import com.demo.entity.TbUsers;

public interface LogService {

	public List<TbUsers> Login(String account,String password);
	public boolean UpdateUserState(String sessionId,String state,String account,String password);
	public boolean UpdateUserStateBySession(String sessionId);
}

ACTION层

package com.demo.action;

import java.io.IOException;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;

import com.demo.dbutil.MySessionContext;
import com.demo.entity.TbUsers;
import com.demo.service.LogService;

public class LogAction {

	private MySessionContext myc = MySessionContext.getInstance();
	private LogService service;
	
	public void setService(LogService service) {
		this.service = service;
	}
	
	public String LogIn() throws Exception{
		HttpServletResponse response = ServletActionContext.getResponse();
		response.setCharacterEncoding("UTF-8");
		HttpServletRequest request=ServletActionContext.getRequest();
		HttpSession session = request.getSession(true);
		session.setMaxInactiveInterval(60*30);//60*30秒失效
		String account = null;
		String password = null;
		List<TbUsers> list = null;
		String re = null;
		if(request.getParameter("account")!=null){
			account = request.getParameter("account").toString();
			password = request.getParameter("password").toString();
		}
		try{
			list = service.Login(account, password);
		}catch(Exception e){
			e.printStackTrace();
			re = "unusual";
		}
		if(list!=null){
			if(list.get(0).getUserD().equals("0")){
				if(service.UpdateUserState(session.getId(),"1", account, password)){
					myc.addSession(session);
					re = "success";
				}else{
					re = "error";
				}
			}else{
				if(service.UpdateUserState("","0", account, password)){
					re = "exist";
				}else{
					re = "error";
				}
				//存在则断开session
				HttpSession sess = myc.getSession(list.get(0).getUserC());
				if(sess!=null){
					myc.delSession(sess);
					sess.invalidate();
				}
				
			}
			
		}else{
			re = "error";
		}
		
		try {
			response.getWriter().write(re);
		} catch (IOException e) {
			// TODO Auto-generated catch block e.printStackTrace();
		}
		list = null;
		return null;
	}
	
	
}

日志测试类

package com.demo.z_Test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogBack_Test {
	
	private static final Logger logger = LoggerFactory.getLogger(LogBack_Test.class);
	public static void main(String[] args) {
		
		//LogBack打印日志测试
		for(int i=0;i<10;i++){
			logger.trace("打印第:" + i + " 个日志,trace");  
			logger.debug("打印第:" + i + " 个日志,debug");  
			logger.info("打印第:" + i + " 个日志,info");  
			logger.warn("打印第:" + i + " 个日志,warn");  
			logger.error("打印第:" + i + " 个日志,error");
		}
		
        
	}

}

关于USERS的实现可以自由完成,此处不再提供

工程文件链接审核通过后附上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪悟道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值