zoukankan      html  css  js  c++  java
  • Java学习札记2013

     

    Java学习札记2013

     

     

     

    姓名:刘显安

     

     

     

    2013年3月11日

     

     

    第一个月:

    20130311:

    内存溢出的三种形式:

    1. 堆溢出:

    /**

    * @author LXA

    * 堆溢出

    */

    public class Heap

    {

        public static void main(String[] args)

        {

            ArrayList list=new ArrayList();

            while(true)

            {

                list.add(new Heap());

            }

        }

    }

    报错:

    java.lang.OutOfMemoryError: Java heap space

    1. 栈溢出:

    /**

    * @author LXA

    * 栈溢出

    */

    public class Stack

    {

        public static void main(String[] args)

        {

            new Stack().test();

        }

        public void test()

        {

            test();

        }

    }

    报错:

    java.lang.StackOverflowError

    1. 方法区溢出

    20130312:

    集合

    线程

    数据库

    20130313:

    数据库连接池:

    反射:

    package C_20130313_反射;

    import java.lang.reflect.Method;

    class User

    {

        private String name;

        public User(){}

        public User(String name)

        {

            this.name=name;

        }

        public void say()//无参的方法

        {

            System.out.println("大家好,我叫"+name+"");

        }

        public void say(String str)//有参的方法

        {

            System.out.println("大家好,我叫"+name+""+str+",我是有参的方法!");

        }

    }

    /**

    * @author LXA

    * 反射最简单的例子

    */

    public class反射

    {

        public static void main(String[] args) throws Exception

        {

            Class c=Class.forName("C_20130313_反射.User");//通过反射找到对应的类

            Method m1=c.getMethod("say");//找到名字叫做say、且无参的方法

            Method m2=c.getMethod("say",String.class);//找到名字叫做say、且有一个String类型参数的方法

            m1.invoke(c.newInstance());//注意newInstance()调用的是无参的构造方法!!!

            m2.invoke(new User("刘显安"),"哈哈");//通过有参的构造方法实例化一个对象

        }

    }

    静态代理

    动态代理:

    文件IO:

    Socket编程:

    20130314:

    模拟Tomcat:

    20130318(Struts)

    20130319(Hibernate)

    缓存策略

    保存策略

    加载策略

    单向关联

    双向关联

    20130320(Spring)

    最近一直在搞正则表达式

    20130322(周五,上课最后一天):

    23号开始做项目了。

    今天碰到的奇葩事情:

    public static void main(String[] args) throws Exception

    {

        File file=new File("F:\\1.txt");

        System.out.println(file.exists());

        FileReader fr=new FileReader(new File("F:\\1.txt"));

    }

    输出结果如下:

    但是如果代码改为如下:

    public static void main(String[] args) throws Exception

    {

        File file=new File("F:\\1.txt");发生

        System.out.println(file.exists());

        FileReader fr=new FileReader(file);

    }

    就不会有任何错误,真是奇葩!!!谁能解释一下不?

    20130325:

    敲代码第一天:

    发现Eclipse一个很不好的地方:运行时不会自动给你保存,而MyEclipse会给你自动保存!

    20130326:

    今天改写jstl。

    关于Java的值传递与引用传递:

    其实这个问题很好理解:

    Java参数,不管是原始类型还是引用类型,传递的都是副本,也就是把参数复制一份再传过去,但是:

    如果参数类型是原始类型,那么直接把这个参数的值复制一份传过去,所以如果在函数中改变了副本的值,原始的值是不会改变的。

    如果参数类型是引用类型,那么传过来的就是这个参数的地址的副本,如果在函数中没有改变这个副本的地址,而是改变了地址所指向的东西,那么在函数内的改变肯定会影响到传入的参数。但是如果在函数中改变了副本的地址(比如new一个,那么副本就指向了一个新的地址),此时在函数里面做的所有修改都针对是对那个新地址所指向的对象,所以原始的值不会改变。

    多说无益,看下面最简单的例子:

    class Student

    {

        int age=20;//学生的初始年龄设置为20

    }

    public class T

    {

        public static void main(String[] args)

        {

            Student stu=new Student();

            System.out.println("学生初始年龄:"+stu.age);

            update(stu); //stu作为参数传过去

            System.out.println("修改后的学生年龄:"+stu.age);

        }

        public static void update(Student stu)

        {

            stu.age=21;

        }

    }

    输出结果:

    学生初始年龄:20

    修改后的学生年龄:21

    如果将update方法改为如下:

    public static void update(Student stu)

    {

        stu=new Student();//此时stu指向的是一个新地址

        stu.age=21;

    }

    那么输出结果将变成:

    学生初始年龄:20

    修改后的学生年龄:20

    注意:虽然上面说如果是引用类型会改变原始值,但是对于final的对象就不灵验了,比如String就是final的,因为final类是不可改变的,所以当改变了String的值时其实又new了一个String,自然原始值是不会跟着改变的(Integer等包装类都是final的)。

    其实这就解释了为什么用String和StringBuffer做参数结果不一样。

    Hibernate注解的使用:

    注解和xml配置差不多,但能够少一半的文件,并且由于一般实体类的大部分属性都不需要配置什么,所以用配置文件会感觉有很大的冗余,这时注解就会大有用处!

    1. 导包:

      在MyEclipse9中,一般导入以下2个库:核心库和注解库

    1. 最简单的实体类(注意注解使用的都是javax.persistence包下面的,别导错包了!):

    package entity;

    import javax.persistence.Basic;

    import javax.persistence.Entity;

    import javax.persistence.Id;

    @Entity

    public class Emp

    {

        @Id

        private int emp_id;//员工ID

        @Basic

        private String emp_name;//员工姓名

    //省略getset

    }

    1. hibernate.cfg.xml文件:

    本人是在项目根目录下新建一个config"源文件夹",然后将所有配置文件都放在这个文件夹下(注意普通文件夹必须先构建路径使之成为源文件夹),然后使用默认配置文件名称hibernate默认就能够找到它。

    注意:下面2行黄色标注部分先不用看!!!

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

        <property name="show_sql">true</property>

        <property name="format_sql">true</property>

        <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>

        <property name="connection.url"> jdbc:oracle:thin:@localhost:1521:xe</property>

        <property name="connection.username">lxa</property>

        <property name="connection.password">123</property>

        <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>

        <property name="hbm2ddl.auto">create</property>

        <mapping class="entity.Emp"/>

        <mapping resource="entity/Emp.hbm.xml"/>

    </session-factory>

    </hibernate-configuration>

    1. Hibernate工具类的改写(部分代码)

    public class HiberUtil

    {

        private static SessionFactory sessionFactory;//全局的会话工厂

        static

        {

            sessionFactory=new AnnotationConfiguration()

                .configure()

                .addAnnotatedClass(Dept.class) //有多少个实体类就add多少次

                .addAnnotatedClass(Emp.class)

                .buildSessionFactory();

        }

        /**

         * 获取会话

         */

        public static Session getSession()

        {

            return sessionFactory.openSession();

        }

    }

    对于已经注解的实体类,必须还要注册,注册有2种方法

    1、也就是最上面配置文件里面的写法(也就是说除了在实体类的上面加一个@Entity之外,还要在配置文件里map一下):

    <mapping class="entity.Emp"/>

    2、如果不喜欢在配置文件里写map,还可以在代码里注册,其实上面已经给出代码了,就是HiberUtil.java中的addAnnotatedClass()

    补充:

    hbm映射文件和注解可以混用。

    可以发现,如果一个系统里面的实体类很多,那么一个个注册就很麻烦了,为此,本人写了一个简单的工具类来解决这个问题(其实就是类似Spring的包扫描,Spring的注解类之所以不需要注册,是因为它可以在配置文件里指定要扫描的包,不知道为什么hibernate不做这样一个功能!)

    使用方法很简单:

    static

    {

        //以下Hibernate3注册的方法

        AnnotationConfiguration conf =new AnnotationConfiguration().configure();

        PackageHelper.addPackage(conf, "entity");//指定要扫描的包名叫做entity

        sessionFactory = conf.buildSessionFactory();

    }

    PackageHelper.java:

    /**

    * @author LXA

    * 获取某个包下面所有类的工具类

    * 2013/03/26

    */

    public class PackageHelper

    {

        /**

         * Hibernate注解配置对象添加注解类

         * @param conf 配置对象

         * @param packageName 要扫描的包名

         */

        public static void addPackage(AnnotationConfiguration conf,String packageName)

        {

            Set<Class<?>> cs=findClass(packageName);

            for(Class<?> c:cs)

                conf.addAnnotatedClass(c);

            System.out.println("注册所有实体类完毕!");

        }

        /**

         * 找到某一个包下面所有的类

         * @param packageName

         * @return

         */

        public static Set<Class<?>> findClass(String packageName)

        {

            Set<Class<?>> cs=new LinkedHashSet<Class<?>>();

            try

            {

                //获取包名对应的真实物理地址

                URL url = Thread.currentThread().getContextClassLoader().getResource(packageName.replace('.', '/'));

                String packagePath = URLDecoder.decode(url.getFile(), "utf-8");//中文路径会存在乱码问题

                findClass(packageName, packagePath,cs);

            }

            catch (UnsupportedEncodingException e)

            {

                e.printStackTrace();

            }

            return cs;

        }

        /**

         * 递归的一个私有方法,供findClass(String packageName)调用

         * @param packageName

         * @param packagePath

         * @param cs

         */

        private static void findClass(String packageName, String packagePath,Set<Class<?>> cs)

        {

            File dir = new File(packagePath);// 获取此包的目录建立一个File

            if (!dir.exists() || !dir.isDirectory())// 如果不存在或者也不是目录就直接返回

                return;

            File[] dirfiles = dir.listFiles();// 如果存在就获取包下的所有文件包括目录

            for (File file : dirfiles)// 循环所有文件

            {

                if (file.isDirectory())// 如果是目录则继续扫描

                    findClass(packageName + "." + file.getName(),file.getAbsolutePath(),cs);

                else

                {

                    if (file.getName().endsWith(".class"))// 如果是java类文件去掉后面的.class 只留下类名

                    {

                        String className = file.getName().replaceAll(".class$", "");

                        try

                        {

                            // 这里用forName有一些不好,会触发static方法,没有使用classLoaderload干净

                            // Class c=Class.forName(packageName + '.' + className);

                            Class c = Thread.currentThread().getContextClassLoader()

                                .loadClass(packageName + '.' + className);

                            cs.add(c);

                        }

                        catch (ClassNotFoundException e)

                        {

                            e.printStackTrace();

                        }

                    }

                }

            }

        }

    }

    20130327:

    三种常见数据库连接方式:

    MySQL:

    jdbc.driver=com.mysql.jdbc.Driver

    jdbc.url=jdbc:mysql://localhost:3306/test

    jdbc.username=root

    jdbc.password=admin

     

    Oracle:

    jdbc.driver=oracle.jdbc.driver.OracleDriver

    jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:orcl

    jdbc.username=scott

    jdbc.password=tiger

     

    MS SQL Server:

    jdbc.driver= com.microsoft.jdbc.sqlserver.SQLServerDriver

    jdbc.url= jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mssql

    jdbc.username=sa

    jdbc.password=sa

    Hibernate注解进阶:

    • Hibernate的注解本着尽量采用默认设置的原则来减少注解的代码,具体体现请往下看。
    • 实体bean中所有的非static的属性都可以被持久化, 除非你将其注解为@Transient(相当于不让这个属性映射到数据库中去)
    • 所有没有定义注解的属性等价于在其上面添加了@Basic注解. 通过 @Basic注解可以声明属性的获取策略(fetch strategy):
    • 注解可以写在属性上,也可以写在方法上,但应尽量避免2种方法混用:要么都写在属性上,要么都写在get方法上。
    • 你可以在实体bean中使用@Version注解,通过这种方式可添加对乐观锁定的支持,version列可以是numeric类型(推荐方式)也可以是timestamp类型.

    如果想对一个列的属性进行具体设置:

    @Column(name="dept_name_222",length=100,nullable=false)

    private String dept_name;//部门名称

    无注解之属性的默认值

    如果某属性没有注解,该属性将遵守下面的规则:

    • 如果属性为单一类型,则映射为@Basic
    • 否则,如果属性对应的类型定义了@Embeddable注解,则映射为@Embedded
    • 否则,如果属性对应的类型实现了Serializable, 则属性被映射为@Basic并在一个列中保存该对象的serialized版本
    • 否则,如果该属性的类型为java.sql.Clob 或 java.sql.Blob,则作为@Lob并映射到适当的LobType.

    主键生成策略:

    使用@Id注解可以将实体bean中的某个属性定义为标识符(identifier). 该属性的值可以通过应用自身进行设置, 也可以通过Hiberante生成(推荐). 使用 @GeneratedValue注解可以定义该标识符的生成策略:

    AUTO 

    自动,推荐使用,可以是identity column类型,或者sequence类型或者table类型,取决于不同的底层数据库.

    TABLE 

    使用表保存id值

    IDENTITY

    identity column,数据库自带的主键自增策略,如SQL Server和MySQL

    SEQUENCE 

    序列,适用于Oracle

    主键一般定义如下:

    @Id @GeneratedValue(strategy=GenerationType.AUTO)

    private int emp_id;//员工ID

    使用注解实现关联映射:

    多对一:

    员工表:

    @Entity

    public class Emp

    {

        @Id @GeneratedValue(strategy=GenerationType.AUTO)

        private int emp_id;//员工ID

        private String emp_name;//员工姓名

        @ManyToOne

        private Dept deptaa;//对应的部门

        public Emp(){}

        public Emp(String emp_name)

        {

            this.emp_name=emp_name;

        }

    //省略getset

    }

    部门表:

    @Entity

    public class Dept

    {

        @Id @GeneratedValue(strategy=GenerationType.AUTO)

        private int dept_id;//部门ID

        private String dept_name;//部门名称

        @Transient //这个表示emps只是普通字段,不会关联到数据库,相当于"注释"

        private Set<Emp> emps;//员工集合

        public Dept(){}

        public Dept(String dept_name)

        {

            this.dept_name=dept_name;

        }

    //省略getset

    }

    生成的表结构如下:

    Dept:

    Emp:

    生成的外键:

    如果想自己指定emp中外键的列名:

    @ManyToOne

    @JoinColumn(name="fsdfs")

    private Dept deptaa;//对应的部门

    一对多:

    Dept.java:

    @Entity

    public class Dept

    {

        @Id @GeneratedValue(strategy=GenerationType.AUTO)

        private int dept_id;//部门ID

        private String dept_name;//部门名称

        @OneToMany

        private Set<Emp> emps;//员工集合

        public Dept(){}

        public Dept(String dept_name)

        {

            this.dept_name=dept_name;

        }

    //省略getset

    }

    Emp.java(部分代码):

        @Transient //相当于把deptaa给注释掉

        private Dept deptaa;//对应的部门

    此时会生成3张表:

    另外会生成一个中间的"联结表",表名默认是:主表表名+下划线+从表表名,所以这里是:dept_emp

    关于这个中间连接表,Hibernate官方解释如下:

    通过在被拥有的实体端(owned entity)增加一个外键列来实现一对多单向关联是很少见的,也是不推荐的. 我们强烈建议通过一个联接表(join table)来实现这种关联. 通过联接表处理单向一对多关联是首选方式.这种关联通过@JoinTable注解来进行描述(这个JoinTable不重要)。

    当然,如果你不喜欢多一个中间表,可以这样(别的地方都不用改,只需改下面):

    @OneToMany

    @JoinColumn(name="empp_id")//指定从表中外键的名字,此时不会生成中间表

    private Set<Emp> emps;//员工集合

    20130328

    HTTP错误代码表:

    所有 HTTP 状态代码及其定义。 
     代码  指示  
    2xx  
    成功  
    200  
    正常;请求已完成。  
    201  
    正常;紧接 POST 命令。  
    202  
    正常;已接受用于处理,但处理尚未完成。  
    203  
    正常;部分信息返回的信息只是一部分。  
    204  
    正常;无响应已接收请求,但不存在要回送的信息。  
    3xx  
    重定向  
    301  
    已移动请求的数据具有新的位置且更改是永久的。  
    302  
    已找到请求的数据临时具有不同 URI  
    303  
    请参阅其它可在另一 URI 下找到对请求的响应,且应使用 GET 方法检索此响应。  
    304  
    未修改未按预期修改文档。  
    305  
    使用代理必须通过位置字段中提供的代理来访问请求的资源。  
    306  
    未使用不再使用;保留此代码以便将来使用。  
    4xx  
    客户机中出现的错误  
    400  
    错误请求请求中有语法问题,或不能满足请求。  
    401  
    未授权未授权客户机访问数据。  
    402  
    需要付款表示计费系统已有效。  
    403  
    禁止即使有授权也不需要访问。  
    404  
    找不到服务器找不到给定的资源;文档不存在。  
    407  
    代理认证请求客户机首先必须使用代理认证自身。  
    415  
    介质类型不受支持服务器拒绝服务请求,因为不支持请求实体的格式。  
    5xx  
    服务器中出现的错误  
    500  
    内部错误因为意外情况,服务器不能完成请求。  
    501  
    未执行服务器不支持请求的工具。  
    502  
    错误网关服务器接收到来自上游服务器的无效响应。  
    503  
    无法获得服务由于临时过载或维护,服务器无法处理请求。
    -----------------------------------------------------------------------------------------------------------------------
    HTTP 400 - 
    请求无效 
    HTTP 401.1 - 
    未授权:登录失败 
    HTTP 401.2 - 
    未授权:服务器配置问题导致登录失败 
    HTTP 401.3 - ACL 
    禁止访问资源 
    HTTP 401.4 - 
    未授权:授权被筛选器拒绝 
    HTTP 401.5 - 
    未授权:ISAPI  CGI 授权失败  
    HTTP 403 - 
    禁止访问 
    HTTP 403 - 
     Internet 服务管理器 (HTML) 的访问仅限于 Localhost 
    HTTP 403.1 
    禁止访问:禁止可执行访问 
    HTTP 403.2 - 
    禁止访问:禁止读访问 
    HTTP 403.3 - 
    禁止访问:禁止写访问 
    HTTP 403.4 - 
    禁止访问:要求 SSL 
    HTTP 403.5 - 
    禁止访问:要求 SSL 128 
    HTTP 403.6 - 
    禁止访问:IP 地址被拒绝 
    HTTP 403.7 - 
    禁止访问:要求客户证书 
    HTTP 403.8 - 
    禁止访问:禁止站点访问 
    HTTP 403.9 - 
    禁止访问:连接的用户过多 
    HTTP 403.10 - 
    禁止访问:配置无效 
    HTTP 403.11 - 
    禁止访问:密码更改 
    HTTP 403.12 - 
    禁止访问:映射器拒绝访问 
    HTTP 403.13 - 
    禁止访问:客户证书已被吊销 
    HTTP 403.15 - 
    禁止访问:客户访问许可过多 
    HTTP 403.16 - 
    禁止访问:客户证书不可信或者无效 
    HTTP 403.17 - 
    禁止访问:客户证书已经到期或者尚未生效 
    HTTP 404.1 - 
    无法找到 Web 站点 
    HTTP 404 - 
    无法找到文件 
    HTTP 405 - 
    资源被禁止 
    HTTP 406 - 
    无法接受 
    HTTP 407 - 
    要求代理身份验证 
    HTTP 410 - 
    永远不可用 
    HTTP 412 - 
    先决条件失败 
    HTTP 414 - 
    请求 - URI 太长 
    HTTP 500 - 
    内部服务器错误 
    HTTP 500.100 - 
    内部服务器错误 - ASP 错误 
    HTTP 500-11 
    服务器关闭 
    HTTP 500-12 
    应用程序重新启动 
    HTTP 500-13 - 
    服务器太忙 
    HTTP 500-14 - 
    应用程序无效 
    HTTP 500-15 - 
    不允许请求 global.asa 
    Error 501 - 
    未实现 
    HTTP 502 - 
    网关错误 

    20130329:

    今天把整个项目改用SSM框架来写,晚上验收。

    MyBatis的使用:

    MyBatis原名ibatis,是2010年开始改为此名的,据网上介绍说,它相对Hibernate而言优点主要是:半封装轻量级不整合Spring的话只有一个jar包,才685kb),SQL语句还是我们自己写,但从数据中取出来的数据可以直接封装成对象,相比Hibernate为了方便而"牺牲性能",MyBatis二者都考虑了。

    Demo项目结构:

    基本步骤:

    1. 新建一个Java项目
    2. 导入mybatis-3.2.1.jar和MySQL的驱动包
    3. 手工到数据库中建一个名为student的表,字段s_id,s_name,注意s_id设为自增:

     

    1. 实体类:entity.Student.java

    public class Student

    {

        private int s_id;

        private String s_name;

        public Student(){}

    //省略getset

    }

    5、dao.StudentDao.java:

    /**

    * @author LXA

    * 学生类Dao,注意必须是接口

    */

    public interface StudentDao

    {

        public void insert(Student student);//

        public void delete(int s_id);//

        public void update(Student student);//

        public Student getOne(int s_id);//查单个

        public List<Student> getList();//查集合

    }

    1. 映射文件,SQL语句都写在这里面:

    注意里面id都和上面的dao方法对应!

    dao.StudentDaoMap.xml:

    <?xml version="1.0" encoding="UTF-8" ?>

    <!DOCTYPE mapper

    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

    <mapper namespace="dao.StudentDao">

        <insert id="insert" parameterType="entity.Student">

            insert into student(s_name) values(#{s_name})

        </insert>

        <delete id="delete" parameterType="int">

            delete from student where s_id=#{s_id}

    </delete>

    <update id="update" parameterType="entity.Student">

        update student set s_name=#{s_name} where s_id=#{s_id}

    </update>

    <select id="getOne" parameterType="int" resultType="entity.Student">

        select * from student where s_id=#{s_id}

    </select>

    <select id="getList" resultType="entity.Student">

        select * from student

    </select>

    </mapper>

    1. MyBatis配置文件:mybatis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>

    <!DOCTYPE configuration

    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

    "http://mybatis.org/dtd/mybatis-3-config.dtd">

    <configuration>

        <environments default="development">

            <environment id="development">

                <transactionManager type="JDBC" />

                <dataSource type="POOLED">

                    <property name="driver" value="com.mysql.jdbc.Driver" />

                    <property name="url" value="jdbc:mysql://localhost:3306/test" />

                    <property name="username" value="root" />

                    <property name="password" value="1" />

                </dataSource>

            </environment>

        </environments>

        <mappers>

            <mapper resource="dao/StudentDaoMap.xml" />

        </mappers>

    </configuration>

    1. 测试:Test.java

    public static void main(String[] args) throws IOException

    {

        String resource = "mybatis-config.xml";

    Reader reader = Resources.getResourceAsReader(resource);

    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader); //一般一个项目只需要一个factory

    SqlSession session=factory.openSession();//Hibernate一样,一个session对应一个连接

    StudentDao dao=session.getMapper(StudentDao.class); //这个dao建议和session一样,到用的时候再获取,也就是说其生命周期比较短

     

    dao.insert(new Student("王老板"));//增,主键自增

    dao.insert(new Student("刘显安"));

    dao.insert(new Student("小萃"));

    List<Student> list=dao.getList();//

    for(Student student:list)

        System.out.println(student.getS_id()+","+student.getS_name());

     

    dao.update(new Student(22, "小小萃"));//

    Student student=dao.getOne(22);//

    System.out.println("修改之后:"+student.getS_id()+","+student.getS_name());

    dao.delete(22);//

     

    session.commit();//提交

    session.close();//关闭session

    }

    关于MyBatis多个参数的问题:

    先看一下上面的例子:

    <update id="update" parameterType="entity.Student">

        update student set s_name=#{s_name} where s_id=#{s_id}

    </update>

    修改时传入一个Student对象,在SQL中引用对象属性时我们直接用:

    #{属性}即可。

    但是如果传入多个参数呢?

    网上有的用Map方式,有的用Bean方式,最简单的还是下面这样:

    假设某方法如下(当然这个例子不是很恰当):

    public void update(Student student,int abc);//

    因为它有2个参数,所以这样改写:

    public void update(@Param("s")Student student,@Param("abc")int abc);//

    然后映射文件如下:

    <update id="update" parameterType="entity.Student">

    update student set s_name=#{s.s_name} where s_id=#{abc}

    </update>

    意思是:因为有多个参数,所以现在要引用某个参数的属性,需指定其名称以免混淆(这里是s),而名称就是在方法里面用@Param指定的。

    MyBatis的if和sql引用:

    无需多言,看看就能明白:

    /**

    * 查询总的记录条数

    * @return

    */

    public int getCount(@Param("vo")ShiftSheetInfoVO vo);

    映射文件:

    <select id="getCount" resultType="int">

    select count(*) from shift_sheet_info where 1=1

    <include refid="queryLike"/>

    </select>

    <sql id="queryLike">

    <if test="vo.sheet_num!=null and vo.sheet_num !=''">

        and sheet_num like #{vo.sheet_num}

    </if>

    <if test="vo.sheet_name!=null and vo.sheet_name!=''">

        and sheet_name like #{vo.sheet_name}

    </if>

    </sql>

    MyBatis的模糊查询和in语法:

    MyBatis会自动在所有的形如#{s_id}外面加上个单引号,所以模糊查询用不了:

    一般模糊查询语句如下:

    select * from student where s_name like '%萃%'

    (MySQL中单引号和双引号都可用)

    这样写肯定是错误的:

    select * from student where s_name like %'萃'%

    所以在MyBatis中貌似模糊查询用不了,因为:

    不管是#{%s_name%}还是%#{s_name}%都不正确!

     

    下面分析一下in语法行不通的问题:

    当主键为int类型时:

    select * from student where s_id in (1,2,3,5,7)

    当主键为varchar类型时:

    select * from student where s_id in ('安','萃','涛哥')

    因为MyBatis会自动在传入的字符串2边加上单引号,所以如果我们传入的字符串是(即头和尾不要单引号,中间有单引号和逗号):

    安','萃','涛哥

    那么理论上是可以查询的到数据的,但是坑爹的是,MyBatis自动把我们自己的单引号全部给转义了:

    另外说明一点,如果想看到执行后的SQL语句,可以故意把它附近的语句写错,比如上面的我故意把in写成ini,所以肯定会报错,在页面上就可以看到真正的SQL语句了。

    几点总结:

    1. MyBatis的dao让spring管理的方法:所有dao都继承自一个BaseDao,然后在Spring的配置文件中指定BaseDao这一个bean即可,其它继承的Dao都会自动创建Bean。
    2. JSTL的一个小问题:<c:forEach>里面是可以嵌套<c:if>的,只是在你刚开始写的时候IDE可能会提示错误,但是等你写完了就不会再提示了。

    如:

    <c:forEach items="${shift_factory }" var="sf">

            <option value="${sf.codeCoding }"<c:if test="${sf.codeCoding== vo.out_factory}">selected</c:if>>${sf.codeName }</option>

    </c:forEach>

     

    1. MySQL中时间类型一般用java.sql.TimeStamp
    2. MySQL和SQL Server一样有数据库自带的自增属性,不像Oracle还要单独搞一个Sequence,麻烦!
    3. MySQL的分页也比Oracle简单多了,一个limit 20,10即表示每页10条记录、查询第3页,前面一个是索引(从0开始),后面是查询的条数
    4. 浏览器的兼容性还是一个很大的问题!
    5. Hibernate真的是一个重量级框架!很重很重!一个项目中加了Hibernate后启动速度大打折扣!
    6. 注解就是比配置好用,但像MyBatis把原本放在Java代码中的SQL语句放到Xml配置文件中,如果再反过来把SQL语句改用注解来写在Java类中,那真不知道对这说什么好了!个人觉得实在没必要!

     

     

     

     

    SSM整合步骤:

    整个demo程序结构如下,先在数据库手工建一个student的表再往下看:

    1. 导入好多好多包,struts的、mybatis的2个,spring一大堆,自己稍微整理了下:

    1. 和配置SSH类似,web.xml的几个配置:

        <!-- Struts2过滤器 -->

        <filter>

            <filter-name>struts2</filter-name>

            <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

        </filter>

        <!-- Struts2过滤器映射 -->

        <filter-mapping>

            <filter-name>struts2</filter-name>

            <url-pattern>/*</url-pattern>

        </filter-mapping>

          

    <!-- Spring编码过滤器 -->

        <filter>

            <filter-name>encodingFilter</filter-name>

            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>

            <init-param>

                <param-name>encoding</param-name>

                <param-value>UTF-8</param-value>

            </init-param>

        </filter>

        <!-- Spring编码过滤器映射 -->

        <filter-mapping>

            <filter-name>encodingFilter</filter-name>

            <url-pattern>/*</url-pattern>

        </filter-mapping>

     

        <!-- Spring 配置文件的本地路径 -->

        <context-param>

            <param-name>contextConfigLocation</param-name>

            <param-value>classpath:applicationContext.xml</param-value>

        </context-param>

        

        <!-- Spring配置信息加载监听器 Context Listener -->

        <listener>

            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

        </listener>

        <!-- Spring Web请求监听器 -->

        <listener>

            <listener-class>

                org.springframework.web.context.request.RequestContextListener</listener-class>

        </listener>

    1. struts.xml文件,这个太简单,省略了。
    2. 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:context="http://www.springframework.org/schema/context"

    xmlns:tx="http://www.springframework.org/schema/tx"

        xmlns:aop="http://www.springframework.org/schema/aop"

        xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

        http://www.springframework.org/schema/aop

        http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

        http://www.springframework.org/schema/tx

        http://www.springframework.org/schema/tx/spring-tx-3.1.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context-3.1.xsd">

        

        <context:component-scan base-package="action,dao,biz,util,aop"/>

        <!-- 设置Aop -->

        <aop:aspectj-autoproxy proxy-target-class="true"/>

        <!-- 数据源 -->

        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"

            destroy-method="close">        

            <property name="driverClass" value="com.mysql.jdbc.Driver"/>

         <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"/>

         <property name="user" value="root"/>

         <property name="password" value="1"/>

        </bean>

     

        <!-- SessionFactory -->

        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

            <property name="dataSource" ref="dataSource" />

            <!-- 指定Map映射文件的路径 -->

            <property name="mapperLocations" value="classpath:dao/*.xml" />

        </bean>

        <!-- 注册BaseDao -->    

        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

            <property name="basePackage" value="dao"/>

            <property name="markerInterface" value="dao.BaseDao"/>

        </bean>

    </beans>

     

    1. 实体类Student.java,字段就是s_id和s_name2个,代码就略了。
    2. 在dao包下建一个BaseDao.java:

    package dao;

    /**

    * @author LXA

    * 最顶头的dao,所有dao都继承这个接口,目的是为了避免每个dao都在spring中注册

    */

    public interface BaseDao

    {

     

    }

    1. 再在dao包下新建一个StudentDao.java,注意继承自BaseDao.java(注意dao不能使用注解):

    /**

    * @author LXA

    * 学生类DAO,继承自BaseDao,注意是一个接口

    */

    public interface StudentDao extends BaseDao

    {

        public void insert(Student student);//

        public void delete(int s_id);//

        public void update(Student student);//

        public Student getOne(int s_id);//查单个

        public List<Student> getList();//查集合

    }

    1. 映射文件见:MyBatis的使用部分
    2. 业务层:StudentBiz.java:

    @Service

    public class StudentBiz

    {

        @Resource

        private StudentDao dao;

        public Student getOne(int s_id)

        {

            return dao.getOne(s_id);

        }

    }

    1. Action层:StudentAction.java:

    @Controller

    public class StudentAction

    {

        @Resource

        private StudentBiz biz;

        public String login()

        {

            Student student=biz.getOne(18);

            System.out.println(student.getS_name());

            return "ok";

        }

    }

    10、使用浏览器访问指定页面即可。

    20130330:

    基于MySQL的MyBatis分页:

    select * from student limit 20,10;

    以上语句表示每页10条,查询第3页。第一个20表示起始数据的索引(0表示第1条),后面的10表示查询10条记录。

    MyBatis中如下使用:

    StudentDao.java部分代码如下:

        /**

         * 获取学生信息列表

         * @param stu 封装模糊查询的对象

         * @param start 起始记录索引

         * @param pageSize 每一页的大小

         * @return

         */

        public List<Student> getList(@Param("s")Student stu, @Param("start")int start,@Param("pageSize")int pageSize);

    映射文件:

    <select id="getList" resultType="entity.Student">

    select * from student where 1=1

    <if test="s.s_name!=null and s.s_name !=''">

        and s_name like #{s.s_name}

    </if>

    limit #{start},#{pageSize}

    </select>

    显然这样不方便,因为每次调用还要自己计算起始索引,所以还应当在业务层进行二次封装:

    StudentBiz.java部分代码:

    /**

    * 获取学生信息列表

    * @param vo 封装模糊查询的对象

    * @param pageNo 页数

    */

    public List<Student> getList(Student s,int page,int pageSize)

    {

        return dao.getList(s,(page-1)*pageSize,pageSize);

    }

     

    JS中的EL表达式:

    JavaScript中注释过的EL表达式仍然会被编译!(只能说这是EL表达式的一个天大的Bug),比如你写一个错误的EL表达式然后给它注释掉,访问那个页面还是会报错的。

     

    关于Struts执行的流程:

    20130331:

    Eclipse一个不好的地方:

    运行前不会自动保存没有保存的文件!

    启动Eclipse时提示工作空间选择:

    20130412(实习真正第一天):

    关于Struts2与自定义过滤器冲突的问题:

    自定义了一个过滤器,内容如下:

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,

            ServletException

    {

        System.out.println("进入自定义过滤器");

        chain.doFilter(request, response);

    }

    如果自定义的过滤器映射放在struts2的前面,不论是拦截具体的后缀(如*.aaa)还是为/*,2个过滤器都能正常进入:

        <filter>

            <filter-name>test1</filter-name><!-- 自定义过滤器 -->

            <filter-class>filter.StrutsFilter</filter-class>

        </filter>

        <filter-mapping>

            <filter-name>test1</filter-name>

            <url-pattern>/*</url-pattern>

        </filter-mapping>

        

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

    如果自定义过滤器放在了struts2的后面的话:

    1. 如果自定义拦截的时/*,访问struts符合的后缀URL时(如.do,.action等)之进入struts过滤器,否则进入自定义的过滤器。
    2. 如果拦截的是具体的,如*.bbb,那么只有访问的url后缀是bbb时才进入自定义。

     

    总结:一句话,Struts很霸道,如果Struts过滤器放在了前面,那么一旦Struts把URL当成一个action,那么就不会进入自定义过滤器,如果自定义放在了前面,那么好办,一切正常OK!

    个人网站:https://haoji.me
    github:https://github.com/sxei
    博客园:http://www.cnblogs.com/liuxianan
    copyright ©2012-2020 小茗同学

    【转载文章务必保留出处和署名,谢谢!】

  • 相关阅读:
    echo "http://172.17.26.115:8380/?key=%c8%fd%d0%c7%ca%d6%bb%fa%b1%f9%cf%e4" | mail -s "noresult_monitr error" maolingzhi@jd.com
    python实现的文本编辑器
    PyQt写的浏览单web页面的browser
    中非发展基金
    团队介绍
    微众—国内最大的微信公众服务平台
    微软创投加速器简介
    知方可补不足~SQL为大数据引入分区表
    实时监控Cat之旅~介绍与自定义类型在哪里
    EF架构~Cannot attach the file as database
  • 原文地址:https://www.cnblogs.com/liuxianan/p/3018417.html
Copyright © 2011-2022 走看看