因学的东西还给老师,所以现如今又重新学习一遍.
工作需要配置一个框架 SSH嘛,好吧又重新看资料,从头配置
不过版本多样性搞得我眼花缭乱,网上什么都有,每处都只能看懂一部分,finally 结合在一起.
要说复习那就得按部就班,不能一手掌握

工具

  • MyEclipse 2014 GA pro
  • MySQL 5.6.9
  • Hibernate 4.1
  • Spring 3.1
  • Struts 2.1

Hibernate

花了一天时间看够了hibernate,连上了mysql,但不仅仅满足于此

不能理解,下次又得忘.

操作记录:

1.创建一个项目 ssh (Java WebProject)

web3.1

javaversion 1.7

jstl 默认

最后我选择了3.1和1.7图片上是3.0和 1.6

java hsf是什么意思_java hsf是什么意思


这时候webroot 和 src下面都没有 xml文件

2.MyEclipse2014 添加框架就是不一样(接触其他版本少)

添加 sturts

右键项目->MyEclipse->Project Facets

下面选择 struts2.x 弹出界面呢 第一个界面不动

第二个界面修改为 /* 然后

第三个界面只够选了Core 没有勾选Spring Plugin

原因是添加Spring会有此包

finish

然后,又多了几个东西

src下面多了个struts.xml

WEB-INF下面多了个web.xml

web.xml里面配置了struts.xml

<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>

这里也就可以改以后action的访问方式了
而 struts.xml里面 ..却是一片空白,
这个 交给之后添加
添加spring
非要我说 谁先谁后 额是名字问题吧(开玩笑)
还是版本在搞怪,这就不说 管他先拿筷子还是先拿碗能吃就行

右键项目->MyEclipse->Project Facets

下面选择 spring ,弹出界面

版本选择3.1 我最高就3.1既然是学习就学最新的吧.

然后 next ,如图

java hsf是什么意思_hibernate_02


一开始看别人说的步骤 要去掉什么要选择什么特别纠结,那就查呗

Enable AOP Builder 选与不选 在于项目大小 增加耦合度的作用

大型项目翻译上说可以提高性能无所谓了

file : applicationContext.xml这个文件位置可以之后更改,也可以不更改

看需不需要集中管理(分类)

然后嘛 finish就是 ,对于经验不足悟性不够的我们来说,完全明白自己需要哪个包是困难的,使用xml配置 还是困难

这次又多了一些东西

WEB-INF目录下面

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 -->

然后把
<param-value>classpath:applicationContext.xml</param-value>
改为
<param-value>/WEB-INF/applicationContext*.xml,classpath*:applicationContext*.xml</param-value>

默认运行位置为 web-info/classes/app….xml,改了后,可以放在web-info目录,也可以放在 web-info/classes/自定义目录 , 自定义目录下名字以applicationContext开头的即可.

还有两个tld文件 这个就不多说

Src 目录

多了一个 ApplicationContext.xml

内容 除了申明也没有其他内容,这得配置事务等等的时候才用

添加hibernate

步骤:

建一个 根包 比如 app,

- 然后建一个子包比如模块名比如 新闻模块 news

- 然后分别建三个子包 dao , service , controller 即为三层

- 另外在添加一个包 table 用于存放表的实体类 跟上面的三层同级或其他位置

- dao 存放 操作数据库的文件

为什么叫要叫 dao , DAO是Data Access Object 意思意思总之是

存放跟数据库打交道的东西

- 连接数据库

为了方便新建一个数据库连接用于可视化操作,可供多个项目使用

菜单栏 Window->Open Perspective->My Eclipse Database Explorer

右键 new 如图

java hsf是什么意思_xml_03


用了MySql 自然选它,也不知道谁会全部用过,

  • Drver name 别名
  • connection url 连接字符串,有些要写数据库名能写就写
  • user name ,password
  • Driver jARs 驱动jar包,这个网上有,最好跟你数据库版本匹配
  • test Driver 测试连接成功与否 success为成功
  • save password 保存密码
    finish ok

然后添加hibernate

右键项目->MyEclipse->Project Facets

下面选择 hibernate ,弹出界面

java hsf是什么意思_xml_04


选择了我最高版本4.1 next,

不创建hibernate.cfg.xml和sessionFactory.class

整合可以不需要,

测试 的的话有需要勾上

next 如图

java hsf是什么意思_hibernate_05


这里的Specify Spring DataSource connection details?

问的是需不需要在spring的xml 也就是applicationcontext.xml添加

sessionFactory 映射

选择刚才添加的数据库连接

enable dynamic DB table creation 是否启用动态创建数据表功能.不需要就不点 ,然后finish,弹出是否更换操作界面 随便勒.

现在 添加hibernate之后 多了哪些内容呢:
applicationContext.xml:

<bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource">
        <property name="url" value="jdbc:mysql://localhost:3306/"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref bean="dataSource" />
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.MySQLDialect
                </prop>
            </props>
        </property>
    </bean>
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager" />

以上是原版XML配置,之后在做详细修改
一个sessionFactory 的bean 和一个
transactionManager注解需要用到
src目录没有hibernate.cfg.xml,因为我没创建


hibernate 实体表

两种:(我所知)

一种用 注解 在类里面用注解(@xxx的样式)就不需要xml了

一种用 映射 用xml 写属性,不过这种方式会产生大量的配置文件

我选择了注解的方式.

步骤:

1.取保MYSQL服务开启.

2.打开database explorer界面(window-show-view - DB-browser)

3.选择表,右键hibernate reverse

java hsf是什么意思_xml_06


4.在弹出的界面中设置

java hsf是什么意思_hibernate_07


5.next 简单设置

第二个界面,若是多个表有关系的需要使用到,这里是一个表就不管他了,

有经验了在尝试.

此处可以设置的内容: enable many to many one to one 即表间关系

多个表需要勾选

6.next第三个界面 详细设置

- 表名设置和主键设置

java hsf是什么意思_User_08


- 字段设置,最好不要改名字,类型我们可以之后再改

java hsf是什么意思_xml_09


finish.

生成了一个实体类,这时的实体类已经可以用

HibernateSessionFactory.getSession().get(User.class,1)查询到记录了

若之前勾选了创建HibernateSessionFactory的话.

get(实体类.class,表的主键) 1 会被封装成Integer对象

@Entity
@Table(name = "user", catalog = "news") //name表名,catalog 数据库名
public class User implements java.io.Serializable {

    // Fields

    private Integer userId;
    private String username;
    private String password;

若数据类型不对这里修改
applicationcontext.xml里面多了一些内容

<property name="annotatedClasses">
            <list>
                <value>app.news.table.User</value></list>
        </property>

这只是暂时的,我们修改为另一种,自动扫描,之后就不用在
数据表逆向工程,添加的时候勾选
update hibernate configuration with mapping resource location了
将上代码修改为:

<!--自动扫描实体:app.news.table包下的类 -->    
    <property name="packagesToScan"  value="app.news.table" />

多个表生成实体类,就有点高级了,那关系堪比乱==伦
理不清就惨,不过还好可以一次次尝试
一个个生成,不对就勾选其他选项.哈哈
我创建了两个表
一个 User 表

CREATE TABLE `user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(25) NOT NULL,
  `password` varchar(25) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT;

一个UserInfo表

CREATE TABLE `userinfo` (
  `userinfo_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `sex` varchar(10) DEFAULT '男' COMMENT '性别',
  `name` varchar(20) DEFAULT NULL COMMENT '姓名',
  PRIMARY KEY (`userinfo_id`),
  UNIQUE KEY `user_id` (`user_id`),
  KEY `userinfo_ibfk_1` (`user_id`),
  CONSTRAINT `userinfo_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`User_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;

可能逻辑上有问题,只为了测试一种可能性

userinfo表有一个字段是 user_id(外键),对应user表的主键,

userinfo.user_id 设置了两个约束,一个唯一约束,一个外键约束

还有级联,也就是userinfo(从表)user(主表)

主表删除记录,对应的从表中的记录会被删除.

一般来说,从表不应该有没有外键的记录,看需要设置为非空.

好,如下图步骤

1.假若有两张表右键创建

java hsf是什么意思_java hsf是什么意思_10


2.选择POJO,下一步

java hsf是什么意思_java hsf是什么意思_11

applicationContext.xml 又修改成这样了所以替换成自动扫描

<property name="annotatedClasses">
            <list>
                <value>app.news.table.User</value>
                <value>app.news.table.UserInfo</value>
            </list>
        </property>

介样子:

<!--自动扫描实体:app.news.table包下的类 -->    
        <property name="packagesToScan"  value="app.news.table" />

若需要测试hibernate,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>
    <session-factory>

        <!-- 基本配置:JDBC方式 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">123456</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <!-- 扩展配置 -->
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="hibernate.jdbc.fetch_size">100</property>
        <property name="hibernate.jdbc.batch_size">30</property>
        <!-- 领域对象:Annotation注解方式 -->
        <mapping class="app.news.table.User" />
        <mapping class="app.news.table.UserInfo" />
    </session-factory>
</hibernate-configuration>

领域对象 Annotation 注解方式那儿就是 对应的刚创建的两个类
而两个类中的代码有些不是我所想要的结果,所以要修改

User.java

@Table(name = "user", catalog = "news") //catalog就是数据库名
public class User implements java.io.Serializable {

    // 字段
    private Integer userId;
    private String username;
    private String password;
    private Set<UserInfo> userInfos = new HashSet<UserInfo>(0);
    //User需不需要持有userinfo看需求,按逻辑上来说,主表是不需要持有从表的,所以这儿不应该有userinfos
    //它的get方法 一对多,即一个用户账户对应多个用户信息,一对一是一对多的一个特例,之后咱就不用他了
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
    public Set<UserInfo> getUserInfos() {

然后是 UserInfo.java

@Table(name = "userinfo", catalog = "news", uniqueConstraints = @UniqueConstraint(columnNames = "user_id"))//好像这就是外键声明哈
public class UserInfo implements java.io.Serializable {
    // 字段
    private Integer userinfoId;
    private User user;
    //若不需要联合查找这儿只该为Integer user_id,不过为了方便设置为一个对象不错
    private String sex;
    private String name;
    //User 的 get方法,多对一,即多个用户信息对一个用户账户,哈,账户是唯一的,之后修改看变成啥.
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", unique = true)
    public User getUser() {

同时选中两个表创建的POJO对象,是双向一对多关系,我只需要单向关系

即 userinfo 持有 user对象,而user不需要持有userinfo对象,因为user是主表,没有外键,Userinfo 的user_id是外键,设置了唯一性约束,外键约束,所以可以为 OneToOne的关系.

此时我们需要做的是去掉user持有的userinfo对象,和修改userinfo的对应关系.步骤图如下:

java hsf是什么意思_xml_12


1.右键user表,选择hibernate Reverse Engineering ,弹出的界面中设置

不用勾选Update Hibernate configuration…,因之前applicationcontext.xml设置了扫描pojo包的方式,不用单个配置.

2.只设置types

3.什么都不勾选.

User.java :

@Table(name = "user", catalog = "news")
public class User implements java.io.Serializable {
    // 字段
    private Integer userId;
    private String username;
    private String password;

不再持有userinfo对象 独立了.
然后修改或者不修改userinfo
UserInfo.java :

@Table(name = "userinfo", catalog = "news", uniqueConstraints = @UniqueConstraint(columnNames = "user_id"))
public class UserInfo implements java.io.Serializable {
    // 字段
    private Integer userinfoId;
    private User user;
    private String sex;
    private String name;
    //User.user的get方法
    @ManyToOne(fetch = FetchType.LAZY)
    //如果没有将user_id设置为唯一约束,这里就是ManyToOne,
    //而如果你设置了user_id为唯一约束,这里就应该显示的设置为OneToOne
    //虽然结果都一样,唯一约束修改为@OneToOne(fetch = FetchType.LAZY)
    //@OneToOne()里面fetch,为加载自身对象时是否加载引用的对象,
    //LAZY为需要的时候加载,还有一些属性值得一提的是cascade = CascadeType.ALL
    //即@OneToOne(fetch= FethchType.LAZY,cascade = CascadeType.ALL)
    //作用是级联操作,所有操作都是级联,详细百度@onetoone
    //更改后ctrl+shift+o,自动引用删除需要/不需要的包
    @JoinColumn(name = "user_id", unique = true)
    public User getUser() {
        return this.user;
    }

到了这里我才明白之前的一些问题
这里下面可以定义实体类
Include referenced tables (A->B)
同时生成这个表引用的另外一个表的实体类(java文件)
Include referenced tables (A<-B)
同时生成引用这个表的另外一个表的实体类(java文件)
Generate support for ListedTable(fk)->UnlistedTable:
如果当前表格是一个从表,生成当前从表实体类到主表实体类访问
Generate support for UnlistedTable(fk)<- ListedTable:
如果当前实体类是一个主表,生成当前实体类到从表实体类访问
以上是第三个界面的选项, A->B和 A<-B好理解
前者就是在右键table中单个表创建POJO的时候,不仅创建自己,还要创建一个引用的表的实体类. 自己(从表),引用的表(主表),userinfo和user
后者,是创建user(主表)时,并创建一个引用自己的表的实体类(userinfo.java)
最下面的两个选项,不知道是我这两个表体现不出效果的原因,还是怎么的.
不管钩不勾选只要勾选了上面A<-B或 A->B,都没区别.
然后是测试:
首先,我们使用HibernateSessionFactory.java文件测试,其他的麻烦不会.
还有必要文件.hibernate.cfg.xml
上面有文件代码,最关键的是有这两个表的映射

<!-- 领域对象:Annotation注解方式 -->
        <mapping class="app.news.table.User" />
        <mapping class="app.news.table.UserInfo" />

不然会找不到表.
关于这两个文件的创建:
右键项目 选择new,(若列表中有Hibernate sessionFactory,和Hibernate Configuration File直接选择)没有选择 other,在MyEclipse 下面的Hibernate中有这两个选项.
创建的xml没有映射,所以需要将上面的代码粘贴
Test.java 测试 :
在hibernate.cfg.xml session-factory 标签内配置一个属性

<!--  如果使用的是本地事务(jdbc事务) -->
        <property name="hibernate.current_session_context_class">thread</property>

这个的作用是能使用 getCurrentSession()

package app.news.test;

import org.hibernate.Session;

import app.news.dao.hibernate.HibernateSessionFactory;
import app.news.table.User;
import app.news.table.UserInfo;

public class Test {

    public static void main(String[] args) {
        Session  session = HibernateSessionFactory.getSession();
        //获取session,这个session是多例,不是单例,每次getSession()获得的都不是同一个对象
        //Session csession = HibernateSessionFactory.getSessionFactory().getCurrentSession();
        /**
         *  <session-factory>
            <!--  如果使用的是本地事务(jdbc事务) -->
            <property name="hibernate.current_session_context_class">thread</property>
            <!--  * 如果使用的是全局事务(jta事务)-->
            <!-- <property name="hibernate.current_session_context_class">jta</property>-->
         * 将配置放在hihbenrate.cfg.xml session-factory下面
         */
        //获取CurrentSession 这个是单例,获得的是同一个对象,只有在多线程的时候才能体现,在这里是测试不出来的
        /*
         * user 表中有一条记录,  user_id=1,username=admin,password=password
         * userinfo表中有一条记录,userinfo_id=1,user_id=1,sex=男,name=张三
         */
        User user = (User)session.get(User.class, 1);
        //参数为实体类的class,id(这里1 被封装成了integer对象)
        System.out.println("userid:"+user.getUserId());
        System.out.println("username:"+user.getUsername());
        System.out.println("password:"+user.getPassword());
        UserInfo userinfo = (UserInfo)session.get(UserInfo.class, 1);
        System.out.println("userinfo_id:"+userinfo.getUserinfoId());
        System.out.println("userinfo_sex:"+userinfo.getSex());
        System.out.println("userinfo_name:"+userinfo.getName());
        System.out.println("userinfo_user:user_id="+userinfo.getUser().getUserId()+",user_name="+userinfo.getUser().getUsername());
        session.close();
    }
}

结果为:

Hibernate:
select
user0_.user_id as user1_0_0_,
user0_.password as password0_0_,
user0_.username as username0_0_
from
news.user user0_
where
user0_.user_id=?

userid:1
username:admin
password:password

Hibernate:
select
userinfo0_.userinfo_id as userinfo1_1_0_,
userinfo0_.name as name1_0_,
userinfo0_.sex as sex1_0_,
userinfo0_.user_id as user4_1_0_
from
news.userinfo userinfo0_
where
userinfo0_.userinfo_id=?

userinfo_id:1
userinfo_sex:男
userinfo_name:张三
userinfo_user:user_id=1,user_name=admin

如果之前没有查找user,id=1,则
Hibernate:
select
userinfo0_.userinfo_id as userinfo1_1_0_,
userinfo0_.name as name1_0_,
userinfo0_.sex as sex1_0_,
userinfo0_.user_id as user4_1_0_
from
news.userinfo userinfo0_
where
userinfo0_.userinfo_id=?
userinfo_id:1
userinfo_sex:男
userinfo_name:张三
Hibernate:
select
user0_.user_id as user1_0_0_,
user0_.password as password0_0_,
user0_.username as username0_0_
from
news.user user0_
where
user0_.user_id=?
userinfo_user:user_id=1,user_name=admin
这就是fetch @OneToOne(fetch = FetchType.LAZY) ,为 LAZY的结果
调用get其他表对象引用的时候才去查询.
一般来说用tomcat会提示log4j没有配置 配置了有一个好处,显示它不显示的错误.
既然要用就配置一个
log4j.properties为名 创建一个文件,

#OFF,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB,ALL 
#log4j.rootLogger =ALL,systemOut,logFile,logDailyFile,logRollingFile,logMail,logDB 
log4j.rootLogger = ALL,systemOut
log4j.appender.systemOut = org.apache.log4j.ConsoleAppender 
log4j.appender.systemOut.layout = org.apache.log4j.PatternLayout 
log4j.appender.systemOut.layout.ConversionPattern = [%.15p][%-22d{yyyy/MM/dd HH\:mm\:ssS}][%l]%n 
log4j.appender.systemOut.Threshold = WARN 
log4j.appender.systemOut.ImmediateFlush = TRUE 
log4j.appender.systemOut.Target =System.out 
log4j.appender.DailyRollingFileAppender.Encoding=UTF-8

第一行的注释,说关闭这些目标输出systemout是控制台输出,也即是MyEclipse的console,其他的有些是输出到文件输出邮件等等.
rootLogger = ALL , all即输出全部级别,有debug ,info,warn,error等
下面的systemOut.Threshold = WARN 即,输出到控制台的最低级别为warn,低于它的消息就不显示了.更多配置网上查.


Action 文件,作为与页面和service的交集,决定了接收请求和请求处理事项.为了理解就从这里开始.
创建一个Action文件位于app.news.controller包下文件名为LoginAction.java 继承 ActionSupport类属于

com.opensymphony.xwork2.ActionSupport

包,而LoginAction.java文件的包名,为controller为之后的一个问题挖了坑.
且看 LoginAction.java

package app.news.controller;

import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.springframework.stereotype.Controller;
import app.news.table.User;
import com.opensymphony.xwork2.ActionSupport;

@Controller//注入到spring中,有几种:@component 代表中立层 ,@service service层,@Repository dao层
@Results({
            @Result(name="error",location="/pages/error.jsp"),
            @Result(name="success",location="/index.jsp",type="redirect")
        })
public class LoginAction extends ActionSupport {
    String username;//用于接收form表单的 用户名
    String password;//密码 接收属性的变量必须有set方法
    User user;//必须写get and set,普通变量可以不写get,但建议写上
    private static final long serialVersionUID = -6309124769328744856L;
    @Action(value="/news/login")// /news即 namespace 也可以在类声明前写@NameSpace("news"),然后这里只写value="login"
    public String login(){
        System.out.println(username+" "+password);
        System.out.println(user.getUsername()+" "+user.getPassword());
        HttpServletRequest request = ServletActionContext.getRequest();//诚如 asp的request
        System.out.println("user.password:"+request.getParameter("user.password"));//获取传递的参数
        return SUCCESS;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public User getUser(){
        return this.user;
    }
}

使用注解@Controller,即将此类的创建交由Spring 框架管理
使用注解则不需要在struts.xml中配置action
主要使用的几个注解:
@Controller 对象创建交给spring托管,
@NameSpace 命名空间 请求的url需要带这里设置的部分
例如 @NameSpace(“news”),这里写了下面的action就不用加/news/
@Actions 一个方法对应多个请求时使用
例如@Actions({@Action(value=”/namespace/actionName”),..})
@Action 一个请求,有请求名name,和返回处理集results属性
例如 @Action(value=”/news/login”[,results={@Result(name=”success”,location=”/index.jsp”,type=”redirect”),…}])
@Results 返回处理集,需要写在类前面
例如 @Results({
@Result(name=”error”,location=”/pages/error.jsp”),
@Result(name=”success”,location=”/index.jsp”,type=”redirect”)
})
@Result 一个返回处理
例如 @Result(name=”success”,location=”/index.jsp”[,type=”redirect”]),其中 type可以为 redirect和redirectAction等等

一般来说,注解的方式,struts默认会扫描包名是action,struts,struts2等的包名中的类(类名以action结尾或继承了action类的类,ActionSupport实现了Action),如果放Action文件的包名不是这些,则需要指定,否者扫描不到.然后文件有了该写配置了,首先是
struts.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
    <!-- 请求参数的编码方式 -->  
    <constant name="struts.i18n.encoding" value="UTF-8"/>  
    <!-- 当struts.xml改动后,是否重新加载。默认值为false(生产环境下使用),开发阶段最好打开  -->  
    <constant name="struts.configuration.xml.reload" value="true"/>  
    <!-- 是否使用struts的开发模式。开发模式会有更多的调试信息。默认值为false(生产环境下使用),开发阶段最好打开  -->  
    <constant name="struts.devMode" value="false"/>  
    <constant name="struts.multipart.maxSize" value="1000000000000" />  
    <!-- 设置浏览器是否缓存静态内容。默认值为true(生产环境下使用),开发阶段最好关闭  -->  
    <constant name="struts.serve.static.browserCache" value="false" />  
    <!-- 指定被struts2处理的请求后缀类型。多个用逗号隔开 -->  
    <constant name="struts.action.extension" value="ahtml"/>  
    <!-- 指定由spring负责action对象的创建-->   
    <constant name="struts.objectFactory" value="spring" />  
    <!-- 自定义jsp文件命名的分隔符 -->
    <constant name="struts.convention.action.name.separator" value="-" />
    <!-- 该常量指定包作为根包来搜索Action类。
        Convention插件除了扫描默认的action,actions,struts,struts2,还会扫描该常量指定的一个或多个包,
        Convention会试图从指定包中发现Action类。 -->
    <constant name="struts.convention.action.packages" value="app.news.controller" />
</struts>

struts.action.extension 指定请求后缀名,默认是 action,do
这里我改成了 ahtml,请求就得带上 /news/login.ahtml
struts.objectFactory 将Action的创建交由Spring管理,所以 下一个配置
文件
applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    ">

    <!-- 配置数据源:方法一,使用C3P0方式(推荐) -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" 
        destroy-method="close" 
        p:driverClass="com.mysql.jdbc.Driver"
        p:jdbcUrl="jdbc:mysql://localhost:3306/" 
        p:user="root" 
        p:password="123456" />
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <!-- 配置session factory使用的数据源 -->
    <property name="dataSource" ref="dataSource" />
    <!--自动扫描实体 -->    
    <property name="packagesToScan"  value="app.news.table" /> 
    <!-- 配置hibernate的其他属性 -->
    <property name="hibernateProperties">
    <map>
        <entry key="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect" />
        <entry key="hibernate.show_sql" value="true" />
        <entry key="hibernate.format_sql" value="true" />
        <!-- 
                    如是说Spring托管则不需要 Hibernate 管理session
                    开启此线程用于手动管理事务,便于测试,去掉则由spring托管,不能直接使用currentsession
                    所以用服务器整合测试去掉,用main()测试开启或不使用currentsession 
                -->
                <!-- 
                <entry key="hibernate.current_session_context_class" value="thread" /> 
                -->
    </map>
    </property>
    </bean>
    <!-- 加入事务管理切面类的配置-->
    <!-- 创建事务管理器(spring针对hibernate实现的事务管理的切面类) -->
    <bean id="txManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!-- 用注解来实现事务管理 -->    
    <tx:annotation-driven transaction-manager="txManager"/> 


<!--引用其他配置文件    <import resource="applicationContext-other.xml"/>    -->
    <!--声明注解所用的bean,但若有下面的scan则不必出现.后者包含前者 <context:annotation-config />     -->
    <context:component-scan base-package="app.news.*" />
</beans>

仔细对比原来的xml,我修改了连接池,原来是dbcp,现在是c3p0都可以,还有其他几种也可以.

1. dataSource 配置成了c3p0
2. sessionFactory 配置了其他属性其中
3. packagesToScan 属性设置了扫描地方,即app.news.table包
4. txManager 也就是之前的transcationManager,事务管理器
5. <tx>标签需要声明,也就是xml开头的那些链接.xsd
6. tx:annotation-driven 注解方式实现事务,管理器使用了txManager
7. transactionAdvice 事务通知
8. bean hibernateTemplate 方便使用session的工具
9. context:component-scan 扫描使用
10. @Service@Controller@Repository的类,并管理创建他们
11. hibernate.current_session_context_class 作为单独使用hibernate时使用,当使用Spring事务时需要去掉

值得一提的是

<bean id=”hibernateTemplate”
class=”org.springframework.orm.hibernate3.HibernateTemplate”>

Hibernate4 支持了事务并且与Spring3.1的HibernateTemplate冲突 所以需要使用Hibernate提供的session获得方式.例如MyEclipse提供创建的HibernateSessionFactory.java

核心配置文件就是web.xml,struts.xml,applicationContext.xml
hibernate.cfg.xml 无用处.
ps:一般 There is no Action mapped,确认你的包名是否是action/struts
如果不是需要设置struts中的struts.convention.action.packages
若使用了@Controller再检查applicationContext.xml中的

<context:component-scan base-package="app.news.*" />

若还是没有,看你的请求后缀名是否一致,namespace+action名=url+后缀,再就是看,action文件是否以action结尾,或者 此文件是否继承 ActionSupport类.


login.jsp

<form action="/news/login.ahtml" method="post">
        username:<input type="text" name="username" /> <br /> 
        password:<input type="password" name="password" /> <br />
        user.username:<input type="text" name="user.username" /> <br /> 
        user.password:<input type="password" name="user.password" /> <br />  
        <input type="submit" value="login" />
        <input type="reset" value="reset" />
    </form>

为了测试区别两种方式一起,之后查询时使用后者 user对象去查找
输入
admin
admin
useradmin
userpassword
结果为

admin admin//String username , password
useradmin userpassword//User user.username , user.password
user.password:userpassword//request.getParameter("user.password") 此处的user.password是表单中 input标签的name

能得到这些,就可以进行下一步了

前面的都是测试,之后的才是正文

到此注解方面是没有问题了,但还没有写dao,service ,所以开始写吧.

DAO

接口
BaseDAO.java

/** 
 * @Title: BaseDAO.java 
 * @Package com.information.dao 
 * @Description: TODO(基础数据操作接口) 
 * @author Mr.Wang
 * @date 2016年6月13日 上午10:21:37 
 * @version V1.0 
 */ 
package com.information.dao;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.hibernate.criterion.Criterion;

/**
 * @ClassName: BaseDAO 
 * @Description: TODO(底层基础操作接口) 
 * @author Mr.Wang
 * @param <T> 任意实体类
 * @date 2016年6月13日 上午10:26:54
 */
public interface BaseDAO<T>{
    /**
     * @Title: 添加 
     * @Description: TODO(保存所设类型的对象,序列化用于生成主键) 
     * @param @param o
     * @param @return 设定文件 
     * @return Serializable 返回生成的主键 
     */
    public Serializable save(T o);

    /**
     * @Title: 删除 
     * @Description: TODO(删除一个记录) 
     * @param @param o 要删除的对象,包含主键 
     */
    public void delete(T o);

    /**
     * 更新一个对象
     * 
     * @param o
     */
    public void update(T o);

    /**
     * 添加或修改对象
     * 
     * @param o
     */
    public void saveOrUpdate(T o);

    /**
     * 查询
     * @Description: TODO(以完整的 hql语句查询)
     * @param hql from 类名  where field=n
     * @return
     */
    public List<T> find(String hql);

    /**
     * @Description: TODO(这里用一句话描述这个方法的作用) 
     * @param @param c 类.class
     * @param @param crit 规则 Property.eq() Restrictions.eq()...
     * @return T 返回类型 
     */
    public List<T> find(Class<T> c,Criterion criterion);

    /**
     * 查询集合
     * 
     * @param hql ,from 类名  where field = ? and field = ?
     * @param param ,数组代表按顺序代表hql中的?
     * @return 泛型列表
     */
    public List<T> find(String hql, Object[] param);

    /**
     * 查询集合
     * 
     * @param hql ,from 类名  where field = ? and field = ?
     * @param param ,list集合 按顺序代表hql中的?
     * @return 泛型列表
     */
    public List<T> find(String hql, List<Object> param);
    /**
     * 查询集合
     * 
     * @param hql ,from 类名  where field = :param1 and field = :param2
     * @param param ,map键值对集合 按名称代表hql中的?
     * @return 泛型列表
     */
    public List<T> find(String hql, Map<String,Object> param);
    /**
     * 查询集合(带分页)
     * 
     * @param hql ,from 类名 where field = ? and field = ?
     * @param param ,数组参数顺序对应?位置
     * @param page
     *            查询第几页
     * @param rows
     *            每页显示几条记录
     * @return
     */
    public List<T> find(String hql, Object[] param, Integer page, Integer rows);

    /**
     * 查询集合(带分页)
     * 
     * @param hql ,from 类名 where field = ? and field = ?
     * @param param ,集合参数顺序对应?位置
     * @param page
     *            查询第几页
     * @param rows
     *            每页显示几条记录
     * @return
     */
    public List<T> find(String hql, List<Object> param, Integer page,
            Integer rows);

    /**
     * 查询集合(带分页)
     * 
     * @param hql ,from 类名 where field = ? and field = ?
     * @param param ,Map集合参数顺序对应?位置
     * @param page
     *            查询第几页
     * @param rows
     *            每页显示几条记录
     * @return
     */
    public List<T> find(String hql, Map<String,Object> param, Integer page,
            Integer rows);

    /**
     * 获得一个对象
     * 
     * @param c 查询类的class
     *            对象类型
     * @param id    主键,联合主键则是一个完整对象
     * @return Object
     */
    public T get(Class<T> c, Serializable id);

    /**
     * 获得一个对象
     * 同find() 唯一不同只是返回一个元素
     * @param hql
     * @param param 
     * @return Object
     */
    public T get(String hql, Object[] param);

    /**
     * 获得一个对象
     * 
     * @param hql
     * @param param
     * @return
     */
    public T get(String hql, List<Object> param);

    /**
     * 获得一个对象
     * 
     * @param hql
     * @param param
     * @return
     */
    public T get(String hql, Map<String,Object> param);


    /**
     * select count(*) from 类
     * 
     * @param hql
     * @return
     */
    public Long count(String hql);

    /**
     * select count(*) from 类
     * 
     * @param hql
     * @param param
     * @return
     */
    public Long count(String hql, Object[] param);

    /**
     * select count(*) from 类
     * 
     * @param hql
     * @param param
     * @return
     */
    public Long count(String hql, List<Object> param);

    /**
     * 执行HQL语句
     * 
     * @param hql ,from 类名  where field = n
     */
    public Integer executeHql(String hql);

    /**
     * 执行HQL语句
     * 修改操作
     * @param hql ,from 类名 where field = ? and field = ?
     * @param param
     * @return 响应数目
     */
    public Integer executeHql(String hql, Object[] param);

    /**
     * 执行HQL语句
     * 修改操作
     * @param hql ,from 类名 where field = ? and field = ?
     * @param param
     * @return 返回修改的记录数
     */
    public Integer executeHql(String hql, List<Object> param);

    /**
     * 执行HQL语句
     * 修改操作
     * @param hql ,from 类名 where field = :param1 and field = :param2
     * @param param
     * @return 返回修改的记录数
     */
    public Integer executeHql(String hql, Map<String,Object> param);
}

实现类
BaseDAOImpl.java

package com.information.dao.impl;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.springframework.stereotype.Repository;

import com.information.dao.BaseDAO;

@Repository("baseDAO")
@SuppressWarnings("all")
public class BaseDAOImpl<T> implements BaseDAO<T> {

    @Resource
    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory){
        this.sessionFactory = sessionFactory;
    }
    public SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }
    private Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    @Override
    public Serializable save(T o) {
        return this.getCurrentSession().save(o);
    }

    @Override
    public void delete(T o) {
        this.getCurrentSession().delete(o);
    }

    @Override
    public void update(T o) {
        this.getCurrentSession().update(o);
    }

    @Override
    public void saveOrUpdate(T o) {
        this.getCurrentSession().saveOrUpdate(o);
    }

    @Override
    public List<T> find(String hql) {
        return this.getCurrentSession().createQuery(hql).list();
    }

    @Override
    public List<T> find(Class<T> c,Criterion criterion){
        Criteria crit = this.getCurrentSession().createCriteria(c);
        crit.add(criterion);
        return crit.list();
    }

    @Override
    public List<T> find(String hql, Object[] param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                q.setParameter(i, param[i]);
            }
        }
        return q.list();
    }

    @Override
    public List<T> find(String hql, List<Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.size() > 0) {
            for (int i = 0; i < param.size(); i++) {
                q.setParameter(i, param.get(i));
            }
        }
        return q.list();
    }

    @Override
    public List<T> find(String hql, Map<String, Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if(param != null && param.size() > 0 )
        for (String key : param.keySet()) {  
            q.setParameter(key, param.get(key));
        }  
        return q.list();
    }


    @Override
    public List<T> find(String hql, Object[] param, Integer page, Integer rows) {
        if (page == null || page < 1) {
            page = 1;
        }
        if (rows == null || rows < 1) {
            rows = 10;
        }
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                q.setParameter(i, param[i]);
            }
        }
        return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
    }

    @Override
    public List<T> find(String hql, List<Object> param, Integer page,
            Integer rows) {
        if (page == null || page < 1) {
            page = 1;
        }
        if (rows == null || rows < 1) {
            rows = 10;
        }
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.size() > 0) {
            for (int i = 0; i < param.size(); i++) {
                q.setParameter(i, param.get(i));
            }
        }
        return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
    }

    @Override
    public List<T> find(String hql, Map<String, Object> param, Integer page,
            Integer rows) {
        if (page == null || page < 1) {
            page = 1;
        }
        if (rows == null || rows < 1) {
            rows = 10;
        }
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.size() > 0) {
            for (String key : param.keySet()) {
                q.setParameter(key, param.get(key));
            }
        }
        return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
    }

    @Override
    public T get(Class<T> c, Serializable id) {
        return (T) this.getCurrentSession().get(c, id);
    }


    @Override
    public T get(String hql, Object[] param) {
        List<T> l = this.find(hql, param);
        if (l != null && l.size() > 0) {
            return l.get(0);
        } else {
            return null;
        }
    }

    @Override
    public T get(String hql, List<Object> param) {
        List<T> l = this.find(hql, param);
        if (l != null && l.size() > 0) {
            return l.get(0);
        } else {
            return null;
        }
    }

    @Override
    public T get(String hql,Map<String,Object> param){
        List <T> l = this.find(hql,param);
        if (l != null && l.size() > 0) {
            return l.get(0);
        } else {
            return null;
        }
    }


    @Override
    public Long count(String hql) {
        return (Long) this.getCurrentSession().createQuery(hql).uniqueResult();
    }

    @Override
    public Long count(String hql, Object[] param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                q.setParameter(i, param[i]);
            }
        }
        return (Long) q.uniqueResult();
    }

    @Override
    public Long count(String hql, List<Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.size() > 0) {
            for (int i = 0; i < param.size(); i++) {
                q.setParameter(i, param.get(i));
            }
        }
        return (Long) q.uniqueResult();
    }

    @Override
    public Integer executeHql(String hql) {
        return this.getCurrentSession().createQuery(hql).executeUpdate();
    }

    @Override
    public Integer executeHql(String hql, Object[] param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.length > 0) {
            for (int i = 0; i < param.length; i++) {
                q.setParameter(i, param[i]);
            }
        }
        return q.executeUpdate();
    }

    @Override
    public Integer executeHql(String hql, List<Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.size() > 0) {
            for (int i = 0; i < param.size(); i++) {
                q.setParameter(i, param.get(i));
            }
        }
        return q.executeUpdate();
    }

    @Override
    public Integer executeHql(String hql, Map<String, Object> param) {
        Query q = this.getCurrentSession().createQuery(hql);
        if (param != null && param.size() > 0) {
            for (String key :param.keySet()) {
                q.setParameter(key, param.get(key));
            }
        }
        return q.executeUpdate();
    }


}

Service

例如用户接口

/** 
 * @Title: LoginService.java 
 * @Package com.information.service.impl 
 * @Description: TODO(登录操作) 
 * @author Mr.Wang
 * @date 2016年6月13日 下午3:50:04 
 * @version V1.0 
 */ 
package com.information.service;

import com.information.table.User;


/** 
 * @ClassName: LoginService 
 * @Description: TODO(用于用户相关服务) 
 * @author Mr.Wang
 * @date 2016年6月13日 下午3:50:04  
 */
public interface UserService {
    /**
     * @Title: checkLogin 验证登录 
     * @Description: TODO(用以验证登录信息) 
     * @param @param user 用户对象 Administrator
     * @return User 返回匹配对象 
     */
    public User checkLogin(User user);
    /**
     * @Title: modifyUser 修改用户 
     * @Description: TODO(修改用户密码) 
     * @param @param user 用户对象
     * @return boolean 修改成功与否 
     */
    public boolean modifyUserPassword(User user);
}

实现类

/** 
 * @Title: UserServiceImpl.java 
 * @Package com.information.service.impl 
 * @Description: TODO(用于User表相关操作) 
 * @author Mr.Wang
 * @date 2016年6月13日 下午3:59:43 
 * @version V1.0 
 */ 
package com.information.service.impl;

import java.util.List;

import javax.annotation.Resource;

import org.hibernate.criterion.Property;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.information.dao.BaseDAO;
import com.information.service.UserService;
import com.information.table.User;

/** 
 * @ClassName: UserServiceImpl 
 * @Description: TODO(用于User表相关操作) 
 * @author Mr.Wang
 * @date 2016年6月13日 下午3:59:43  
 */
@Transactional
@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource(name="baseDAO")
    BaseDAO<User> dao;
    @Override
    public User checkLogin(User user) {
        if(user == null)return null;
        Property uname = Property.forName("username");
        List<User> list = dao.find(User.class, uname.eq(user.getUsername()));
        if(list!=null && list.size()>0){
            User temp = list.get(0);
            if(temp.equals(user.getPassword()))return temp;
        }
        return null;
    }
    @Override
    public boolean modifyUserPassword(User user) {
        if(user == null)return false;
        if(user.getPassword() == null || user.getPassword().length()>25 || user.getPassword().length() < 5)return false;
        String hql= "update User user set user.password=? where user.userId="+user.getUserId();
        int changeCount = dao.executeHql(hql,new String[]{user.getPassword()});
        if(changeCount>0)return true;
        return false;
    }

}

一开始我还打算每个表写一个dao,看了别人的代码才有所感悟,底层写一个就是了,UserService只提供两个(暂时)接口,一个check,一个modify,但实现这两个方法的内部就不一定了
内部:

public User checkLogin(User user) {
        if(user == null)return null;//空就返回
        Property uname = Property.forName("username");
        List<User> list = dao.find(User.class, uname.eq(user.getUsername()));
        //这里其实使用的是
        //public List<T> find(Class<T> c,Criterion criterion);
        //内部
        /*
Criteria crit = this.getCurrentSession().createCriteria(c);
        crit.add(criterion);//标准查询,按照标准规则设置查询条件查询
        return crit.list();
        */
        //它需要一个Criterion对象,这个对象可由
        //property.forname("类属性名").eq("类属性值")获得
        //当然Property类提供了大量的方法例如,eq/isNull/ne/or/and/order等,相当于== <> or and
        if(list!=null && list.size()>0){
            User temp = list.get(0);
            if(temp.equals(user.getPassword()))return temp;
        }
        return null;
    }

此处没有使用HQL所以没发现一个问题,而modify则发现了

public boolean modifyUserPassword(User user) {
        if(user == null)return false;//空则返回false
        if(user.getPassword() == null || user.getPassword().length()>25 || user.getPassword().length() < 5)return false;//密码不符合规则返回false,相当于再次确认当然应该用正则表达式来更好
        String hql= "update User user set user.password=? where user.userId="+user.getUserId();//HQL语句
        int changeCount = dao.executeHql(hql,new String[]{user.getPassword()});//使用数组参数
        if(changeCount>0)return true;//判断修改数确定返回值
        return false;
    }

此处使用 dao.executeHql(),参数为 String hql, Object[] param
使用setParameter(index,param)的形式 ,而这就是一个配置问题的入口
使用HQL,需要创建

Query q = this.getCurrentSession().createQuery(hql);

而创建Query,中含有参数的时候却有一个异常抛出

"java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I"

引起异常的是 jar包冲突,一个是 Struts中的 antlr2.7.2另一个是Hibernate的antlr2.7.7,去掉2.7.2即可

java hsf是什么意思_java hsf是什么意思_13


在window-preferences中

至此,查询和修改都没错误了,不知道之后还有什么情况

2017年5月22日 补充:具体引用的包


Spring

java hsf是什么意思_hibernate_14


Struts

java hsf是什么意思_User_15


Hibernate

java hsf是什么意思_User_16

若有错-To be continue…