精华内容
下载资源
问答
  • mybatis五表联合操作

    2020-03-12 00:12:00
    ,建立表结构 1,users 用户表 ...五表的逻辑关系图 1,pom文件添加junit,mysql, mybatis(3.4.4) 2,设置mybatis的配置文件 <?xml version="1.0" encoding="UTF-8" ?> <!DO...

    一,建立表结构
    1,users 用户表
    2,orders 订单表
    3, details 订单详细信息表
    4,products 产品表
    5,types 产品类别表
    注:五表的逻辑关系图
    在这里插入图片描述
    1,pom文件添加junit,mysql, mybatis(3.4.4)

    2,设置mybatis的配置文件

    <?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节点
            里面有配置信息 分别是环境和映射
             其中环境里有datasource,里面有我们熟悉的连接数据库的四个字符串
    -->
    <configuration>
    
        <!--
            引入db的配置文件信息,后面用到的四个连接字符串就可以直接使用 ${}的方式来动态引入
        -->
        <properties resource="db.properties" />
    
        <!--
            给当前mybatis项目添加日志功能,该STDOUT_LOGGING值的好处是不用添加第三方jar包就可以有日志的输出
        -->
        <settings>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${user}"/>
                    <property name="password" value="${pass}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="com/qfedu/mapper/OrderMapper.xml"/>
            <mapper resource="com/qfedu/mapper/UserMapper.xml"/>
            <mapper resource="com/qfedu/mapper/DetailMapper.xml"/>
            <mapper resource="com/qfedu/mapper/ProductMapper.xml"/>
            <mapper resource="com/qfedu/mapper/TypeMapper.xml"/>
        </mappers>
    </configuration>
    
    

    3,db.properties数据库的配置文件

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mall
    user=root
    pass=12345678
    
    

    4,设计pojo类

    5,设置映射文件mapper
    1,OrderMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="com.qfstu.pojo.OrderMapper">
    
        <select id="getOrderByOid" resultMap="orderMap">
            select * from orders where oid = #{oid}
        </select>
    
        <resultMap id="orderMap" type="com.qfstu.pojo.Order">
    
            <!--
                id代表主键,分别设置列和属性的对应关系
            -->
            <id property="oid" column="oid" ></id>
    
            <!--
                result代表普通字段的映射,分别指定列与属性的对应
    
                如果字段名和属性名一致,可以省略
    
                属性名叫做payType,字段名pay_type;
                <result column="pay_type" property="payType" />
            -->
            <result column="price" property="price" />
            <result column="addr" property="addr" />
            <result column="payType" property="payType" />
    
            <!--
                association关联,只要是"对一"的关系都可以使用association,代表关联
                property代表Order类中的属性名u
                column代表Orders表中的uid字段
                select代表要使用该查询完成两表的联合查询得出user对象
            -->
            <association property="u" column="uid" select="com.qfstu.pojo.UserMapper.getUserByUid"></association>
    
            <collection property="details" column="oid" select="com.qfstu.pojo.DetailMapper.getDetailsByOid" ofType="com.qfstu.pojo.Detail"/>
    
        </resultMap>
    </mapper>
    

    2,UserMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="com.qfstu.pojo.UserMapper">
    
        <select id="getUserByUid" resultType="com.qfstu.pojo.User">
            select * from users where uid = #{uid}
        </select>
    </mapper>
    

    3,DetailMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="com.qfstu.pojo.DetailMapper">
    
        <select id="getDetailsByOid" resultMap="detailMap">
            select * from details where oid = #{oid}
        </select>
    
        <resultMap id="detailMap" type="com.qfstu.pojo.Detail">
            <id column="did" property="did"></id>
    
            <result property="count" column="count" />
    
            <association property="pro" column="pid" select="com.qfstu.pojo.ProductMapper.getProductByPid" />
        </resultMap>
    
    </mapper>
    

    4,ProductMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="com.qfstu.pojo.ProductMapper">
    
        <select id="getProductByPid" resultMap="productMap">
            select * from products where pid = #{uid}
        </select>
    
        <resultMap id="productMap" type="com.qfstu.pojo.Product">
            <id column="pid" property="pid"></id>
    
            <association property="t" column="tid" select="com.qfstu.pojo.TypeMapper.getTypesByTid" />
        </resultMap>
    
    </mapper>
    

    5,TypeMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="com.qfstu.pojo.TypeMapper">
    
        <select id="getTypesByTid" resultType="com.qfstu.pojo.Types">
            select * from types where tid = #{tid}
        </select>
    </mapper>
    

    6,TestOrder.java

    package com.qfstu.test;
    
    import com.qfstu.pojo.Order;
    import com.qfstu.pojo.User;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.IOException;
    
    
    /**
     * Created by 86150 on 2020/3/10.
     */
    public class TestOrders {
    
        private SqlSessionFactory sf=null;
    
        private SqlSession session=null;
    
        @Before
        public void setUp(){
            try{
                sf = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
    
                session = sf.openSession(true);
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    
        @After
        public void tearDown(){
            if (session!=null){
                session.close();
                session=null;
            }
        }
    
    
        @Test
        public void testGetOrderByOid(){
            Order order = session.selectOne("com.qfstu.pojo.OrderMapper.getOrderByOid", "f8fb1b8a62db11eaa2c13d7cb7217e15");
            System.out.println(order);
        }
        
    }
    
    

    运行结果

    Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    PooledDataSource forcefully closed/removed all connections.
    Opening JDBC Connection
    Created connection 1791868405.
    ==>  Preparing: select * from orders where oid = ? 
    ==> Parameters: f8fb1b8a62db11eaa2c13d7cb7217e15(String)
    <==    Columns: oid, price, addr, payType, uid
    <==        Row: f8fb1b8a62db11eaa2c13d7cb7217e15, 30998, beijingxisanqi, zhibubao, 1
    ====>  Preparing: select * from users where uid = ? 
    ====> Parameters: 1(Integer)
    <====    Columns: uid, name, pass, phone
    <====        Row: 1, wukong, 888888, 13488071376
    <====      Total: 1
    ====>  Preparing: select * from details where oid = ? 
    ====> Parameters: f8fb1b8a62db11eaa2c13d7cb7217e15(String)
    <====    Columns: did, count, pid, oid
    <====        Row: 63ba6caa62dc11eaa2c13d7cb7217e15, 2, 06d7903f62da11eaa2c13d7cb7217e15, f8fb1b8a62db11eaa2c13d7cb7217e15
    ======>  Preparing: select * from products where pid = ? 
    ======> Parameters: 06d7903f62da11eaa2c13d7cb7217e15(String)
    <======    Columns: pid, name, img, price, tid
    <======        Row: 06d7903f62da11eaa2c13d7cb7217e15, iphone x, iphone.jpg, 9999, d96cac00628111eaa2c13d7cb7217e15
    ========>  Preparing: select * from types where tid = ? 
    ========> Parameters: d96cac00628111eaa2c13d7cb7217e15(String)
    <========    Columns: tid, name
    <========        Row: d96cac00628111eaa2c13d7cb7217e15, digit
    <========      Total: 1
    <======      Total: 1
    <====        Row: ade6d49962dc11eaa2c13d7cb7217e15, 1, 778619ce62da11eaa2c13d7cb7217e15, f8fb1b8a62db11eaa2c13d7cb7217e15
    ======>  Preparing: select * from products where pid = ? 
    ======> Parameters: 778619ce62da11eaa2c13d7cb7217e15(String)
    <======    Columns: pid, name, img, price, tid
    <======        Row: 778619ce62da11eaa2c13d7cb7217e15, yagao, heiren.jpg, 99, d090dec4628111eaa2c13d7cb7217e15
    ========>  Preparing: select * from types where tid = ? 
    ========> Parameters: d090dec4628111eaa2c13d7cb7217e15(String)
    <========    Columns: tid, name
    <========        Row: d090dec4628111eaa2c13d7cb7217e15, house
    <========      Total: 1
    <======      Total: 1
    <====        Row: b7fa3ada62dc11eaa2c13d7cb7217e15, 1, aa0f109e62d911eaa2c13d7cb7217e15, f8fb1b8a62db11eaa2c13d7cb7217e15
    ======>  Preparing: select * from products where pid = ? 
    ======> Parameters: aa0f109e62d911eaa2c13d7cb7217e15(String)
    <======    Columns: pid, name, img, price, tid
    <======        Row: aa0f109e62d911eaa2c13d7cb7217e15, mac pro, mac.jpg, 21999, d96cac00628111eaa2c13d7cb7217e15
    <======      Total: 1
    <====      Total: 3
    <==      Total: 1
    Order{oid='f8fb1b8a62db11eaa2c13d7cb7217e15', price=30998.0, addr='beijingxisanqi', payType='zhibubao', u=User{uid=1, name='wukong', pass='888888', phone='13488071376'}, details=[Detail{did='63ba6caa62dc11eaa2c13d7cb7217e15', count=2, pro=Product{pid='06d7903f62da11eaa2c13d7cb7217e15', name='iphone x', img='iphone.jpg', price=9999.0, t=Types{tid='d96cac00628111eaa2c13d7cb7217e15', name='digit'}}}, Detail{did='ade6d49962dc11eaa2c13d7cb7217e15', count=1, pro=Product{pid='778619ce62da11eaa2c13d7cb7217e15', name='yagao', img='heiren.jpg', price=99.0, t=Types{tid='d090dec4628111eaa2c13d7cb7217e15', name='house'}}}, Detail{did='b7fa3ada62dc11eaa2c13d7cb7217e15', count=1, pro=Product{pid='aa0f109e62d911eaa2c13d7cb7217e15', name='mac pro', img='mac.jpg', price=21999.0, t=Types{tid='d96cac00628111eaa2c13d7cb7217e15', name='digit'}}}]}
    Closing JDBC Connection [com.mysql.jdbc.JDBC4Connection@6acdbdf5]
    Returned connection 1791868405 to pool.
    
    Process finished with exit code 0
    
    展开全文
  • :代码已托管在GitHub上,地址是:https://github.com/Damaer/Mybatis-Learning ,项目是mybatis-11-one2one,需要自取,需要配置...所谓查询,举个例子:我们有很多国家,每个国家只有个领导人(...

    注:代码已托管在GitHub上,地址是:https://github.com/Damaer/Mybatis-Learning ,项目是mybatis-11-one2one,需要自取,需要配置maven环境以及mysql环境(sql语句在resource下的test.sql中),觉得有用可以点个小星星,小菜鸟在此Thanks~

    所谓一对一多表查询,举个例子:我们有很多国家,每一个国家只有一个领导人(假设),我们需要根据id查询国家信息,带上领导人的信息。

    创建数据表

    设计表的时候,我们需要考虑由于是一对多关系,我们需要在国家表里面使用一个字段对应领导人的信息。

    #创建数据库
    CREATE DATABASE `test` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
    #创建数据表
    CREATE TABLE `test`.`country` ( `cid` INT(10) NOT NULL AUTO_INCREMENT ,`cname` VARCHAR(20) NOT NULL ,`mid` INT(10) NOT NULL,PRIMARY KEY(`cid`)) ENGINE = MyISAM;
    CREATE TABLE `test`.`minister` ( `mid` INT(10) NOT NULL AUTO_INCREMENT ,`mname` VARCHAR(20) NOT NULL,PRIMARY KEY(`mid`)) ENGINE = MyISAM;
    
    #初始化数据表
    INSERT INTO `country` (`cid`, `cname`, `mid`) VALUES ('1', 'aaa', '1'); 
    INSERT INTO `country` (`cid`, `cname`, `mid`) VALUES ('2', 'bbb', '2');
    INSERT INTO `country` (`cid`, `cname`, `mid`) VALUES ('3', 'ccc', '3'); 
    
    INSERT INTO `minister` (`mid`, `mname`) VALUES ('1', 'sam'); 
    INSERT INTO `minister` (`mid`, `mname`) VALUES ('2', 'jane'); 
    INSERT INTO `minister` (`mid`, `mname`) VALUES ('3', 'jone'); 
    

    数据表如下:



    实体类

    country对应的实体类:

    public class Country {
    	private Integer cid;
    	private String cname;
    	private Minister minister;
    
    	public Integer getCid() {
    		return cid;
    	}
    
    	public void setCid(Integer cid) {
    		this.cid = cid;
    	}
    
    	public String getCname() {
    		return cname;
    	}
    
    	public void setCname(String cname) {
    		this.cname = cname;
    	}
    
    	public Minister getMinister() {
    		return minister;
    	}
    
    	public void setMinister(Minister minister) {
    		this.minister = minister;
    	}
    
    	@Override
    	public String toString() {
    		return "Country{" +
    						"cid=" + cid +
    						", cname='" + cname + '\'' +
    						", minister=" + minister +
    						'}';
    	}
    }
    
    

    Minister对应的实体类:

    public class Minister {
    	private Integer mid;
    	private String mname;
    	@Override
    	public String toString() {
    		return "Minister [mid=" + mid + ", mname=" + mname + "]";
    	}
    	public Integer getMid() {
    		return mid;
    	}
    	public void setMid(Integer mid) {
    		this.mid = mid;
    	}
    	public String getMname() {
    		return mname;
    	}
    	public void setMname(String mname) {
    		this.mname = mname;
    	}
    	
    }
    

    MybatisUtils工具类,用于获取单例的sqlSession对象:

    public class MyBatisUtils {
        static private SqlSessionFactory sqlSessionFactory;
    
        static public SqlSession getSqlSession() {
            InputStream is;
            try {
                is = Resources.getResourceAsStream("mybatis.xml");
                if (sqlSessionFactory == null) {
                    sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
                }
                return sqlSessionFactory.openSession();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
    }
    
    

    在mybatis.xml里面注册mapper文件:

    <mappers>
        <mapper resource="mapper/mapper.xml"/>
    </mappers>
    

    我们的两个接口(对应mapper文件中的两个sql语句):

    public interface ICountryDao {
    	Country selectCountryById(int cid);
    	Country selectCountryById2(int cid);
    }
    

    mapper文件,有两种写法,一种是嵌套结果,一种是嵌套查询,嵌套结果的就是使用一条sql完成查询,需要在自己定义的resultMap里面使用来组织结果属性,嵌套查询也有一个,但是在最外面的标签并没有将所有需要的东西查询出来,而是在里面指定需要关联查询的sql语句的id,这样的方式就是懒加载:

    <?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.ICountryDao">
    <!-- 	resultMap 能解决字段和属性不一样的问题 -->
    	<!-- 以后用得比较多 ,是因为可以使用延迟加载-->
    	<!-- 嵌套查询 -->
    	<select id="selectMinisterByCountry" resultType="Minister">
    	select mid,mname from minister where mid=#{ooo}
    	</select>
    	<resultMap type="Country" id="countryMapper">
    		<id column="cid" property="cid"/>
    		<result column="cname" property="cname"/>
    		<!-- country中有一个成员变量是ministers,它的泛型是Minister -->
    		<association property="minister"
    					select="selectMinisterByCountry"
    					column="mid">
    		</association>
    	</resultMap>
    	<select id="selectCountryById" resultMap="countryMapper">
    		select cid,cname,mid
    		from country 
    		where 
    		cid=#{cid}
    	</select>
    
        <!-- 嵌套结果-->
        <select id="selectCountryById2" resultMap="countryMapper2">
            select * from country c,minister m where c.mid = m.mid and c.cid= #{cid}
        </select>
        <resultMap id="countryMapper2" type="Country">
            <id column="cid" property="cid"/>
            <result column="cname" property="cname"/>
            <association property="minister" javaType="Minister">
    			<id property="mid" column="mid"/>
    			<result property="mname" column="mname"/>
    		</association>
        </resultMap>
    </mapper>
    

    单元测试:

    public class MyTest {
      private ICountryDao dao;
      private SqlSession sqlSession;
      @Before
      public void Before(){
        sqlSession=MyBatisUtils.getSqlSession();
        dao=sqlSession.getMapper(ICountryDao.class);
      }
      @Test
      public void TestselectCountryById(){
        Country country=dao.selectCountryById(1);
        System.out.println(country);
      }
    
      @Test
      public void TestselectCountryById2(){
        Country country=dao.selectCountryById2(1);
        System.out.println(country);
      }
    
    
      @After
      public void after(){
        if(sqlSession!=null){
          sqlSession.close();
        }
      }
    
    }
    

    结果:

    [service] 2018-07-12 15:23:38,971 - dao.ICountryDao.selectCountryById -537  [main] DEBUG dao.ICountryDao.selectCountryById  - ==>  Preparing: select cid,cname,mid from country where cid=? 
    [service] 2018-07-12 15:23:39,004 - dao.ICountryDao.selectCountryById -570  [main] DEBUG dao.ICountryDao.selectCountryById  - ==> Parameters: 1(Integer)
    [service] 2018-07-12 15:23:39,037 - dao.ICountryDao.selectMinisterByCountry -603  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ====>  Preparing: select mid,mname from minister where mid=? 
    [service] 2018-07-12 15:23:39,037 - dao.ICountryDao.selectMinisterByCountry -603  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - ====> Parameters: 1(Integer)
    [service] 2018-07-12 15:23:39,040 - dao.ICountryDao.selectMinisterByCountry -606  [main] DEBUG dao.ICountryDao.selectMinisterByCountry  - <====      Total: 1
    [service] 2018-07-12 15:23:39,041 - dao.ICountryDao.selectCountryById -607  [main] DEBUG dao.ICountryDao.selectCountryById  - <==      Total: 1
    Country{cid=1, cname='aaa', minister=Minister [mid=1, mname=sam]}
    

    此文章仅代表自己(本菜鸟)学习积累记录,或者学习笔记,如有侵权,请联系作者删除。人无完人,文章也一样,文笔稚嫩,在下不才,勿喷,如果有错误之处,还望指出,感激不尽~

    技术之路不在一时,山高水长,纵使缓慢,驰而不息。

    公众号:秦怀杂货店

    展开全文
  • 、数据库建表 1、Users 用户 ...之间的逻辑关系如下图所示 二、代码时间实现 1、pom.xml添加 mysql、junit、mybatis依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns...

    一、数据库建表
    1、Users 用户表
    2、Products 商品表
    3、Types 商品类别表
    4、Orders 订单表
    5、Details 订单详情表
    注:表之间的逻辑关系如下图所示
    在这里插入图片描述
    二、代码时间实现
    1、pom.xml添加 mysql、junit、mybatis依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.qfedu</groupId>
        <artifactId>Day22_mybatis</artifactId>
        <version>1.0-SNAPSHOT</version>
    
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>
    </dependencies>
    </project>
    

    2、对五个表进行封装
    User.java

    package com.qfedu.pojo;
    
    /**
     * Created by sun on 2020/3/10.
     */
    public class User {
        private int uid;
        private String name;
        private String pass;
        private String phone;
    
        @Override
        public String toString() {
            return "User{" +
                    "uid=" + uid +
                    ", name='" + name + '\'' +
                    ", pass='" + pass + '\'' +
                    ", phone='" + phone + '\'' +
                    '}';
        }
    
        public int getUid() {
            return uid;
        }
    
        public void setUid(int uid) {
            this.uid = uid;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPass() {
            return pass;
        }
    
        public void setPass(String pass) {
            this.pass = pass;
        }
    
        public String getPhone() {
            return phone;
        }
    
        public void setPhone(String phone) {
            this.phone = phone;
        }
    }
    
    

    Order.java

    package com.qfedu.pojo;
    
    import java.util.List;
    
    /**
     * Created by sun on 2020/3/10.
     */
    public class Order {
        private String oid;
        private double price;
        private String addr;
        private String payType;
        private User u;
        private List<Detail> detail;
    
        @Override
        public String toString() {
            return "Order{" +
                    "oid='" + oid + '\'' +
                    ", price=" + price +
                    ", addr='" + addr + '\'' +
                    ", payType='" + payType + '\'' +
                    ", u=" + u +
                    ", detail=" + detail +
                    '}';
        }
    
        public List<Detail> getDetail() {
            return detail;
        }
    
        public void setDetail(List<Detail> detail) {
            this.detail = detail;
        }
    
        public String getAddr() {
            return addr;
        }
    
        public void setAddr(String addr) {
            this.addr = addr;
        }
    
        public String getPayType() {
            return payType;
        }
    
        public void setPayType(String payType) {
            this.payType = payType;
        }
    
        public User getU() {
            return u;
        }
    
        public void setU(User u) {
            this.u = u;
        }
    
        public String getOid() {
            return oid;
        }
    
        public void setOid(String oid) {
            this.oid = oid;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    }
    
    

    Detail.java

    package com.qfedu.pojo;
    
    /**
     * Created by sun on 2020/3/10.
     */
    public class Detail {
        private String did;
        private int count;
        private Product p;
    
        @Override
        public String toString() {
            return "Detail{" +
                    "did='" + did + '\'' +
                    ", count=" + count +
                    ", p=" + p +
                    '}';
        }
    
        public String getDid() {
            return did;
        }
    
        public void setDid(String did) {
            this.did = did;
        }
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
    
    
        public Product getP() {
            return p;
        }
    
        public void setP(Product p) {
            this.p = p;
        }
    }
    
    

    Product.java

    package com.qfedu.pojo;
    
    /**
     * Created by sun on 2020/3/10.
     */
    public class Product {
        private String pid;
        private String name;
        private String img;
        private double price;
        private Type t;
    
        @Override
        public String toString() {
            return "Product{" +
                    "pid='" + pid + '\'' +
                    ", name='" + name + '\'' +
                    ", img='" + img + '\'' +
                    ", price=" + price +
                    ", t=" + t +
                    '}';
        }
    
        public String getPid() {
            return pid;
        }
    
        public void setPid(String pid) {
            this.pid = pid;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getImg() {
            return img;
        }
    
        public void setImg(String img) {
            this.img = img;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        public Type getT() {
            return t;
        }
    
        public void setT(Type t) {
            this.t = t;
        }
    }
    
    

    Type.java

    package com.qfedu.pojo;
    
    /**
     * Created by sun on 2020/3/10.
     */
    public class Type {
        private String tid;
        private String name;
    
        @Override
        public String toString() {
            return "Type{" +
                    "tid='" + tid + '\'' +
                    ", name='" + name + '\'' +
                    '}';
        }
    
        public String getTid() {
            return tid;
        }
    
        public void setTid(String tid) {
            this.tid = tid;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    

    3、配置数据库信息
    sql.properties

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mall
    user=root
    pass=123456
    

    4、配置mybatis.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节点
            里面有配置信息 分别是环境和映射
             其中环境里有datasource,里面有我们熟悉的连接数据库的四个字符串
    -->
    <configuration>
    
        <properties resource="sql.properties" >
            <property name="pass" value="123456"></property>
        </properties><!--属性-->
    
    
        <!--
            给当前mybatis项目添加日志功能,该STDOUT_LOGGING值的好处是不用添加第三方jar包就可以有日志的输出
        -->
        <settings><!--全局配置参数-->
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
        <typeAliases>
            <package name="com.qfedu.pojo" />
    
        </typeAliases>
        <environments default="development"><!--环境集合属性对象-->
            <environment id="development"><!--环境子属性对象-->
                <transactionManager type="JDBC"/><!--事务管理-->
                <dataSource type="POOLED"><!--数据源-->
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${user}"/>
                    <property name="password" value="${pass}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers><!--映射器-->
            <mapper resource="com.qfedu.mapper/OrderMapper.xml"/>
            <mapper resource="com.qfedu.mapper/UserMapper.xml"/>
            <mapper resource="com.qfedu.mapper/DetailMapper.xml"/>
            <mapper resource="com.qfedu.mapper/ProductMapper.xml"/>
            <mapper resource="com.qfedu.mapper/TypeMapper.xml"/>
        </mappers>
    </configuration>
    

    5、创建映射文件nameMapper.xml
    注:(1)多表联合操作时,注意防止出现递归现象
    (2) association关联,只要是"对一"的关系都可以使用association,代表关联
    collection 关联 是设置集合,只要是“对多”关系,都可以用collection代表集合
    OrderMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="OrderMapper">
    
        <select id="getOrderByOid" resultMap="orderMap">
            select * from orders where oid = #{oid}
        </select>
    
        <resultMap id="orderMap" type="com.qfedu.pojo.Order">
    
            <!--
                id代表主键,分别设置列和属性的对应关系
            -->
            <id property="oid" column="oid" ></id>
    
            <!--
                result代表普通字段的映射,分别指定列与属性的对应
    
                如果字段名和属性名一致,可以省略
    
                属性名叫做payType,字段名pay_type;
                <result column="pay_type" property="payType" />
            -->
            <result column="price" property="price" />
            <result column="addr" property="addr" />
            <result column="payType" property="payType" />
    
            <!--
                association关联,只要是"对一"的关系都可以使用association,代表关联
                property代表Order类中的属性名u
                column代表Orders表中的uid字段
                select代表要使用该查询完成两表的联合查询得出user对象
            -->
            <association property="u" column="uid" select="UserMapper.getUserByUid"></association>
            <!--collection 设置集合,只要是“对多”关系,都可以用collection代表集合
            column代表的是orders表与details表关联的字段-->
            <collection property="detail"  column="oid" select="DetailMapper.getDetailByOid" ofType="detail"/>
        </resultMap>
    </mapper>
    

    UserMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="UserMapper">
    
        <select id="getUserByUid" resultType="com.qfedu.pojo.User">
            select * from users where uid = #{uid}
        </select>
    </mapper>
    

    DetailMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="DetailMapper">
    
        <select id="getDetailByOid" resultMap="detailMap">
            select * from details where oid = #{oid}
        </select>
    
        <resultMap id="detailMap" type="com.qfedu.pojo.Detail">
            <id column="did" property="did"></id>
    
            <result property="count" column="count" />
    
            <association property="p" column="pid" select="ProductMapper.getProductByPid" />
        </resultMap>
    </mapper>
    

    ProductMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="ProductMapper">
    
        <select id="getProductByPid" resultMap="productMap">
            select * from products where pid = #{pid}
        </select>
    
        <resultMap id="productMap" type="com.qfedu.pojo.Product">
            <id column="pid" property="pid"></id>
    
            <association property="t" column="tid" select="TypeMapper.getTypesByTid" />
        </resultMap>
    </mapper>
    

    TypeMapper.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,
        每个方法对应自己的sql语句,每个sql语句对应有一个id
        整个项目中所有的namespace.id必须是唯一的
    -->
    <mapper namespace="TypeMapper">
    
        <select id="getTypesByTid" resultType="com.qfedu.pojo.Type">
          select * from types where tid = #{tid}
        </select>
    </mapper>
    

    6、创建测试类OrderTest.java

    package com.qfedu.test;
    
    import com.qfedu.pojo.Order;
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.IOException;
    
    
    /**
     * Created by sun on 2020/3/10.
     */
    public class OrderTest {
        private SqlSessionFactory sf=null;
        private SqlSession ss=null;
        @Before
        public void before(){
            try {
                sf=new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
                ss=sf.openSession();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        @After
        public void after(){
            if(ss!=null){
                ss.close();
                ss=null;
            }
        }
        @Test
        public void ordertest(){
            Order order=ss.selectOne("OrderMapper.getOrderByOid","c406647d62d411ea997c0d34dcb6fac2");
            System.out.println(order);
        }
    }
    
    
    展开全文
  • !册!

    2016-10-16 14:42:16
    、自定义协议的调用         、注册表的概念 在谈及Windows自定义协议之前,不得不预先介绍的是注册表这个概念。注册表是windows操作系统的个核心数据库,其作用是充当计算机上操作系统和应用程序的中央...

    引用:http://www.cnblogs.com/leslies2/p/3727762.html

    目录

    一、注册表的概念

    二、以C#程序修改注册表

    三、在 HKEY_CLASSES_ROOT 中添加自定义协议

    四、通过“安装项目”方式修改注册表

    五、自定义协议的调用

     

     

     

     

    一、注册表的概念

    在谈及Windows自定义协议之前,不得不预先介绍的是注册表这个概念。注册表是windows操作系统的一个核心数据库,其作用是充当计算机上操作系统和应用程序的中央信息储存库,用于存放着各种系统级参数。它能直接控制着windows的启动、硬件驱动程序的装载以及一些windows应用程序的运行。
    注册表中保存有应用程序和资源管理器外壳的初始条件、首选项和卸载数据等,联网计算机的整个系统的设置和各种许可,文件扩展名与应用程序的关联,硬件部件的描述、状态和属性,性能记录和其他底层的系统状态信息,以及其他数据等。

    1.1 打开注册表

    打开 "windows运行",然后输入regedit或regedt32即可打开注册表

     

    1.2 注册表结构

    注册表由键、子键和值项构成,一个键就是分支中的一个文件夹,而子键就是这个文件夹中的子文件夹,子键同样是一个键。一个值项则是一个键的当前定义,由名称、数据类型以及分配的值组成。一个键可以有一个或多个值,每个值的名称各不相同,如果一个值的名称为空,则该值为该键的默认值。

    HKEY_CLASSES_ROOT 用于控制所有文件的扩展和所有可执行文件相关的信息,本章提到的Windows自定义协议也是在此项中注册产生的(在后面章节将详细讲述);

    HEKY_CURRENT_USER  用于管理系统当前的用户信息,及其应用程序的相关资料,例如:当前登录的用户信息,包括用户登录用户名和暂存的密码、当前用户使用的应用软件信息等。用户登录时,其信息会在HEKY_USER表中拷贝到此表中,当HEKY_USER表中信息发生改动时,HEKY_CURRENT_USER表中的信息也将随之改动;

    HKEY_CURRENT_MACHINE 用于存储控制系统和软件的信息,当中包括网络和硬件上所有的软件设备信息,比如文件的位置,注册和未注册的状态,版本号等等;比较常用的例如在HKEY_LOCAL_MACHINE\Microsoft\Windows\CurrentVersion\Run下注册程序,程序就会在Windows启动时自动运行等等。其实在HKEY_LOCAL_MACHINE\SOFTWARE\Classes里面就包含了HKEY_CLASSES_ROOT信息,而HKEY_CLASSES_ROOT只是它的一个键值的映射,方便信息管理而已;

    HEKY_USER  作用是把缺省用户和目前登陆用户的信息输入到注册表编辑器,但它仅被那些配置文件激活的登陆用户使用。当任何在HKEY_CURRENT_USER里的信息发生改变,HKEY_USERS里面的信息也会相应改动。

    HKEY_CURRENT_CONFIG 用于存储当前系统的配置方式,例如当Windows为同一个硬件安装有多种驱动程序时,会在HEKY_CUREENT_MACHINE中记录多个程序信息,而在HEKY_CURRENT_CONFIG中只是存储默认使用的驱动信息,Windows 启动时会默认按照HEKY_CURRENT_CONFIG中的配置调用相关的驱动程序;

    回到目录

     

    二、以C#程序修改注册表

    微软建立了Registry、RegistryKey 常用类用于修改Windows 注册表中的节点。

    2.1 Registry 类

    Registry 主要用作获取 Windows 注册表中的根项的 RegistryKey 对象,并提供访问项/值对的static 方法。
    它有以下几个常用的属性可直接用于获取HEKY_CUREENT_MACHINE、HKEY_CLASSES_ROOT等几个基础项

    属性 说明
    ClassesRoot 定义文档的类型(或类)以及与那些类型关联的属性。 该字段读取 Windows 注册表基项 HKEY_CLASSES_ROOT。
    CurrentConfig 包含有关非用户特定的硬件的配置信息。 该字段读取 Windows 注册表基项 HKEY_CURRENT_CONFIG。
    CurrentUser 包含有关当前用户首选项的信息。 该字段读取 Windows 注册表基项 HKEY_CURRENT_USER
    DynData 已过时包含动态注册表数据。 该字段读取 Windows 注册表基项 HKEY_DYN_DATA。
    LocalMachine 包含本地计算机的配置数据。 该字段读取 Windows 注册表基项 HKEY_LOCAL_MACHINE。
    PerformanceData 包含软件组件的性能信息。 该字段读取 Windows 注册表基项 HKEY_PERFORMANCE_DATA。
    Users 包含有关默认用户配置的信息。 该字段读取 Windows 注册表基项 HKEY_USERS。

    Registry属性表2.1.1

     

    Registry 也提供几个常用方法用于获取或设置注册表中指定名称的项值。

    方法 说明
    GetValue (String, String, Object) 检索与指定的注册表项中的指定名称关联的值。  如果在指定的项中未找到该名称,则返回您提供的默认值;或者,如果指定的项不存在,则返回 null    
    SetValue(String, String, Object)   设置指定的注册表项的指定名称/值对。  如果指定的项不存在,则创建该项。    
    SetValue(String, String, Object, RegistryValueKind)   通过使用指定的注册表数据类型,设置该指定的注册表项的名称/值对。  如果指定的项不存在,则创建该项。    

    Registry方法表2.1.2

     

    2.2 RegistryKey 类

    RegistryKey类主要用于管理 Windows 注册表中的项级节点,通过 Registry 类的属性就可以获取注册表中的根节点。它包含了以下几个常用属性   

    属性 说明
    Handle 获取一个 SafeRegistryHandle 对象,该对象表示当前 RegistryKey 对象封装的注册表项。
    Name 检索项的名称。
    SubKeyCount 检索当前项的子项数目。
    ValueCount 检索项中值的计数。
    View 获取用于创建注册表项的视图。

    RegistryKey属性表2.2.1

     

    RegistryKey类的方法比较多,通过CreateSubKey(String)、GetValue(String)、SetValue(String, Object)、DeleteValue(String)等常用方法,就可以实现对注册表的查询修改。下面简单介绍一下RegistryKey的几个常用方法   

    方法 说明
    Close() 关闭该项,如果该项的内容已修改,则将该项刷新到磁盘。
    CreateSubKey(String) 创建一个新子项或打开一个现有子项以进行写访问。
    CreateSubKey(String, RegistryKeyPermissionCheck) 使用指定的权限检查选项创建一个新子项或打开一个现有子项以进行写访问。
    CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions) 使用指定的权限检查和注册表选项,创建或打开一个用于写访问的子项。
    CreateSubKey(String, RegistryKeyPermissionCheck, RegistrySecurity) 使用指定的权限检查选项和注册表安全性创建一个新子项或打开一个现有子项以进行写访问。
    CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions, RegistrySecurity) 使用指定的权限检查选项、注册表选项和注册表安全性,创建或打开一个用于写访问的子项。
    DeleteSubKey(String) 删除指定的子项。
    DeleteSubKey(String, Boolean) 删除指定的子项,并指定在找不到该子项时是否引发异常。
    DeleteSubKeyTree(String) 递归删除子项和任何子级子项。
    DeleteSubKeyTree(String, Boolean) 以递归方式删除指定的子项和任何子级子项,并指定在找不到子项时是否引发异常。
    DeleteValue(String) 从此项中删除指定值。
    DeleteValue(String, Boolean) 从此项中删除指定的值,并指定在找不到该值时是否引发异常。
    Flush() 将指定的打开注册表项的全部特性写到注册表中。
    GetSubKeyNames() 检索包含所有子项名称的字符串数组。
    GetValue(String) 检索与指定名称关联的值。  如果注册表中不存在名称/值对,则返回 null 
    GetValue(String, Object) 检索与指定名称关联的值。  如果未找到名称,则返回您提供的默认值。 
    GetValue(String, Object, RegistryValueOptions) 检索与指定的名称和检索选项关联的值。  如果未找到名称,则返回您提供的默认值。 
    SetValue(String, Object) 设置指定的名称/值对。

    RegistryKey方法表2.2.2


    2.3 应用实例

    下面先通过几个例子,简单介绍一下如何通过 Registry、RegistryKey 类修改系统注册表。

    2.3.1 新建自定义的项

    下面应用程序将会在注册表中新建 MyApplication项,并在其子项Path的默认值中保存应用程序的StartupPath、在AppPath值中保存应用程序的UserAppDataPath

    复制代码
            static void Main(string[] args)
            {
                //获取Machine根项
                RegistryKey machine = Registry.LocalMachine;
                //打开SOFTWARE项
                RegistryKey software = machine.OpenSubKey("SOFTWARE", true);
                //新项MyApplication项
                RegistryKey myApplication = software.CreateSubKey("MyApplication");
                RegistryKey subkey = myApplication.CreateSubKey("Path");
                //新建键值,当键值名称为空时,将被设置为默认值
                subkey.SetValue(null, Application.StartupPath);
                subkey.SetValue("AppPath", Application.UserAppDataPath);
            }
    复制代码

    运行应用程序后,打开"windows运行",然后输入regedit,在注册表LocalMachine项中可以查找到新建的MyApplication项

     

    2.3.2 开机启动 “命令提示符”

    注册表所包含的信息很多,其中在“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run”处正是用于Windows开机启动的程序信息。下面以Windows自带的“命令提示符”工具为例子,通过修改注册表实现开机启动。(说明:"命令提示符"的路径是在“C:\Windows\System32\cmd.exe”)

    复制代码
          static void Main(string[] args)
            {
                //打开注册表子项
                RegistryKey key = Registry.LocalMachine
                    .OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
                //增加开机启动项
                key.SetValue("Cmd", "C:\\Windows\\System32\\cmd.exe");
            }
    复制代码

    修改后可以看到注册表中在“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run”中会增加了一个名为Cmd的键

    当重启计算机时就会看到“命令提示符”将自动启动

     

    回到目录

     

    三、在 HKEY_CLASSES_ROOT 中添加自定义协议

    上面的章节已经简单介绍如何通过程序操作注册表,下面将介绍一下如果通过修改HKEY_CLASSES_ROOT中的项,建立自定义协议。
    首先建立一个应用程序MyApplication,写入简单的Hello World测试代码

       static void Main(string[] args)
            {
                Console.WriteLine("Hello World");
                Console.ReadKey();
            }

    手动在注册表中建立下面的项和键:

    • 1、在HKEY_CLASSES_ROOT下添加项MyApplication.
    • 2、修改MyApplication项下的默认值输入"URL:(可为空)"。
    • 3、在MyApplication项下再添加一个键值"URL Protocol"。(必要健,否则在IE浏览器中可能无法运行)
    • 4、在MyApplication项下新建项"shell"
    • 5、在shell项下新建项"open"
    • 6、在open项下新建项"command"
    • 7、修改command项的默认键值为MyApplication应用程序的路径 "D:\C# Projects\MyApplication.exe" "%1"

    注意:把 command 键值设置为 "D:\C# Projects\MyApplication.exe" "%1",只要当中包含标示符“%1”,应用程序可以根据自定义协议的路径获取对应的参数,其使用方式将在下面的章节再详细说明。

    简单测试:建立一个HTML页面,如入以下代码。
    注意:此连接路径正是以注册表产首项的MyApplication名称相同。

    复制代码
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
      ......
    </head>
     <body>
         <a href="MyApplication://command">Hello World</a>
       </body>
    </html>

    当按下Hello World连接符时,系统就会调用自定义协议MyApplication,启动“D:\C# Projects\MyApplication.exe”

     

    回到目录

    四、通过“安装项目”方式修改注册表

    4.1 建立应用程序

    上面章节所介绍的只是自定义协议的简单使用方式,然而在做软件项目的时候,无论是使用C/S或者B/S方式,自定义协议都必须实现在客户端的自动安装才能使用,因此客户端的注册表设置只能通过程序进行修改。有见及此,微软早在“安装项目”中设置了注册表修改功能。下面的章节将为大家介绍如何通过 Visual Studio 2010 的“安装项目”,实现注册表的修改。
    建立一个新的MyApplication应用程序,输入以下代码。

    复制代码
        [DataContract]
        public class Person
        {
            [DataMember]
            public int ID;
            [DataMember]
            public string Name;
            [DataMember]
            public int Age;
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                if (args != null)
                {
                    //获取输入参数
                    string data = args[0].Split('&')[1];
                    //把JSON转换成Person对象
                    Person person = GetPerson(data);
                    //数据显示
                    Console.WriteLine(person.Name + "'s age is:" + person.Age);
                    Console.ReadKey();
                }
            }
    
            //数据转换
            static Person GetPerson(string data)
            {
                DataContractJsonSerializer serializer = new 
                    DataContractJsonSerializer(typeof(Person));
                MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(data));
                Person person = (Person)serializer.ReadObject(stream);
                stream.Close();
                return person;
            }
        }
    复制代码

     

    4.2 添加安装项目

    然后在解决方案里面添加一个“安装项目”

    右键点击"安装项目",选择“视图-文件系统”后,在应用程序文件夹中添加当前的“MyApplication”项目。


    4.3 修改注册表

    右键点击"安装项目",选择“视图-注册表”后,按照第三节的例子在HKEY_CLASSES_ROOT上建立多个必要项。为方法获取此应用程序的安装路径,可以在MyApplication项中加入一个键值Path,绑定"[TARGETDIR]",便于系统随时能通过此键值获取应用程序的安装路径。

    在“安装项目”中有多个可用的绑定值,例如:“[TARGETDIR]”用于绑定应用程序的安装路径,“[Manufacturer]”用于绑定应用程序制造商名称等等。在command的值中输入"[TARGETDIR]MyApplication.exe""%1",系统成功安装后,此值就会转换成应用程序的安装路径。例如:MyApplication应用程序安装在"D:\C# Projects"安件夹中,那么注册表的command默认值就会变成“D:\C# Projects\MyApplication.exe” “%1”。

     

    4.4 添加安装自定义操作

    在安装应用程序的前后,很多时候需要做一些必要的操作,例如存储程序的Path值,为应用程序生成一个sn文件作为标识等等。这时候就可以通过建立Installer的子类,在安装的前后的事件进行操作。
    首先建立新项目InstallComponent,在项目中加入一个具备RunInstaller特性的类继承Installer类,RunInstaller特性是作用是用于指示在程序集安装期间是否调用该安装程序。而Installer类是Framework 中所有自定义安装程序的基类,它具备了以下多个方法。    

    方法 说明
    Commit 在派生类中重写时,完成安装事务。
    Install 在派生类中被重写时,执行安装。
    OnAfterInstall 引发 AfterInstall 事件。
    OnAfterRollback 引发 AfterRollback 事件。
    OnAfterUninstall 引发 AfterUninstall 事件。
    OnBeforeInstall 引发 BeforeInstall 事件。
    OnBeforeRollback 引发 BeforeRollback 事件。
    OnBeforeUninstall 引发 BeforeUninstall 事件。
    OnCommitted 引发 Committed 事件。
    OnCommitting 引发 Committing 事件。
    Rollback 在派生类中重写时,还原计算机的安装前状态。
    Uninstall 在派生类中重写时,移除安装。

    Installer方法表4.4.1

    只要自定义的类型继承了Installer类并重写 Install、Commit、Rollback 和 Uninstall 等方法,系统就可以在应用程序安装的多个不同状态下进行操作。下面这个常用例子当中,MyInstaller加入了AfterInstall事件的处理方法,在MyApplication应用程序安装完成后,会根据注册表的Path键值获取应用程序的安装路径,并在该文件夹内加入sn文件。sn文件内存储着一个GUID,作为该应用程序的一个标识。

    复制代码
       [RunInstaller(true)]
        public partial class MyInstaller : Installer
        {
            public MyInstaller()
                : base()
            {
            //绑定完成安装事件的处理方法
                this.AfterInstall += new InstallEventHandler(OnAfterInstall);
            }
    
            /// 加入安装完成后的处理方法
            protected override void OnAfterInstall(object sender, InstallEventArgs e)
            {
                CreateSn();
            }
    
          //在完成安装后建立一个sn文件,对该应用程序进行标识
            private void CreateSn()
            {
                var regKey = Registry.ClassesRoot.OpenSubKey("MyApplication", true);
                if (regKey != null)
                {
                    //根据注册表中的Path键值,获取系统在客户端的安装路径
                    string path = regKey.GetValue("Path").ToString();
                //建立sn文件
                    string snPath = path + "sn";
                    StreamWriter writer = new StreamWriter(snPath, true, Encoding.Unicode);
                    writer.Write(Guid.NewGuid().ToString());
                    writer.Close();
                }
            }
    
            /// 重写安装过程方法
            public override void Install(IDictionary stateSaver)
            {
                base.Install(stateSaver);
            }
    
            /// 重写卸载方法
            public override void Uninstall(IDictionary savedState)
            {
                base.Uninstall(savedState);
            }
    
            /// 重写回滚方法
            public override void Rollback(IDictionary savedState)
            {
                base.Rollback(savedState);
            }
    
            //重写提交方法
            public override void Commit(IDictionary savedState)
            {
                base.Commit(savedState);
            }
        }
    复制代码

     

    4.5 在安装项目中绑定自定义操作

    当完成自定义操作的设定后,回到安装项目,右键点击"安装项目",选择“视图-文件系统”后,在应用程序文件夹中添加自定义操作的“InstallComponent”项目。

    然后右键点击"安装项目",选择“视图-自定义操作-添加自定义操作-应用程序文件夹”,选择刚才导入的 “InstallComponent”项目。

    把安装、提交、回滚、卸载等操作都与InstallComponent的MyInstaller类进行绑定。

     

    生成安装项目后,点击setup应用程序进行系统安装,完成安装后你就会发现在注册表的HKEY_CLASSES_ROOT下将添加了MyApplication项。而且在该应用程序文件夹中会自动增加一个sn文件,里面将保存着一个CUID码。

    回到目录

     

    五、自定义协议的调用

    5.1 以连接方式调用

    调用自定义协议的方式很多,其中最简单的就是以连接方式来调用,好像下面的例子,当页面连接地址为MyApplication://自定义协议时,系统就会自动到注册表查找该协议,根据command默认项的绑定路径对该程序进行调用。并把“MyApplication://command&{'ID':'1','Name':'Rose','Age':'26'}" 路径名作为static void main(string[] args) 方法中的其中一个参数输入。

    复制代码
    <body>
       <script  type="text/javascript">
        window.onload = function () {
            var link = "MyApplication://command&{'ID':'1','Name':'Rose','Age':'26'}";
            location.href = link;
        }
       </script>
    </body>

    观察第4节的内容,自定义协议的main方法会把args[0]参数按照字符'&'进行分组,然后把后面的"{'ID':'1','Name':'Rose','Age':'26'}"JSON字符串转换成Person对象进行显示。

     

    5.2 动态调用

    回顾前面例子,一直都是运用最简单的连接方式对自定义协议进行调用。然而在现实的开展过程中,这种方法并不可行,因为每次调用客户端的自定义协议可能需要不同的参数,把参数直接通过连接路径来传输具有安全性问题。
    最简单的解决方案是把自定义协议的路径在IHttpHandler里面生成,再通过ajax来获取,在回调函数中再调用此协议。通过此方法,协议的路径不会以文本的方式存在于客户端。除非是熟悉开发人员通过测试工具进行逐步检索,否则一般人不能通过页面找到自定义协议信息。
    下面就是一个以IHttpHandler生成自定义协议的一个例子,MyHandler会根据url路径获取请求对象的id值,然后进行数据查询,并把查询到的对象转化为JSON格式。最后把自定义协议的路径返回到客户端。

    复制代码
        [DataContract]
        public class Person
        {
            public Person(int id, string name, int age)
            {
                ID = id;
                Name = name;
                Age = age;
            }
    
            [DataMember]
            public int ID;
            [DataMember]
            public string Name;
            [DataMember]
            public int Age;
        }
    
       public class MyHandler : IHttpHandler
        {
            public bool IsReusable
            {
                get { return true; }
            }
    
            public void ProcessRequest(HttpContext context)
            {
                //通过QueryString获取id
                string data = context.Request.QueryString["id"];
                if (data != null)
                {
                    int id = int.Parse(data);
                    //根据id进行数据查找
                    foreach (var person in DataSource())
                    {
                        if (person.ID == id)
                        {
                            //把Person对象转化为JSON数据
                            string json = ConvertToJson(person);
                            //输出自定义协议路径
                            context.Response.Write(GetUrl(json));
                        }
                    }
                }
            }
    
            //获取自定义协议路径
            private string GetUrl(string json)
            {
                return "MyApplication://command&" + json;
            }
    
            //把Person对象转化为JSON
            private string ConvertToJson(Person person)
            {
                DataContractJsonSerializer serializer = new
                    DataContractJsonSerializer(typeof(Person));
                MemoryStream stream = new MemoryStream();
                serializer.WriteObject(stream, person);
                byte[] bytes = stream.ToArray();
                stream.Close();
                return Encoding.ASCII.GetString(bytes);
            }
    
            //模拟数据源
            private IList<Person> DataSource()
            {
                IList<Person> list = new List<Person>();
                Person person1 = new Person(1, "Rose", 34);
                list.Add(person1);
                ......
                return list;
            }
        }
    复制代码

    客户端通过ajax把id发送到MyHandler.ashx进行查询,在回调函数中调用所获取到的自定义协议。
    如果自定义协议参数中具有保密资料的信息还可以通过加密方式进行传递,好像上面的一个例子,客户端可以先把自动生成的sn发送到服务器进行记录,并与客户ID进行绑定。在请求自定义协议的路径时通过IHttpHandler把相关的信息通过sn进行加密,等到数据发送到客户端后再进行解密。

    复制代码
    <head>
        <title></title>
        <script src="Scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
    </head>
    <body>
       <a name="send" id="send" href="#">GetPerson</a>
       <script type="text/javascript">
           $(function () {
               $('#send').click(function () {
                   $.ajax({
                       type: "GET",
                       url: "MyHandler.ashx?id=1",
                       data: null,
                       dataType: null,
                       success: function (data) {
                           location.href = data;
                       }
                   });
               });
           });
       </script>
    </body>
    </html>
    复制代码

    回到目录 

     

    本章小结

    自定义协议有着广泛的应用,像QQ、迅雷、淘宝等等这些的常见的应用程序都会使用自定义协议。特别在大型的企业系统开发过程中,C/S、B/S融合开发的情况很常见,这时候自定义协议更发挥其独特的作用。一般在系统自动更新,客户端信息获取等这些功能上都会使用自定义协议进行开发。相对于ActiveX控件,自定义协议不会受到浏览器的约束,更能简化客户端与浏览器之间的信息传信。

    对 .NET 开发有兴趣的朋友欢迎加入QQ群:230564952共同探讨 !

     

    C#综合揭秘

    通过修改注册表建立Windows自定义协议
    Entity Framework 并发处理详解
    细说进程、应用程序域与上下文
    细说多线程(上)
    细说多线程(下)
    细说事务

    深入分析委托与事件


    展开全文
  • iptables 防火墙、iptables概述二、netfilter/iptables关系三、四表五链3.1 四3.2 链3.3 规则链之间的匹配顺序3.3.1 主机型防火墙3.3.2 网络型防火墙3.3.3 规则链内的匹配顺序四、iptables的安装4.1 iptables...
  • list类型其实就是个双向链表,通过 push pop 操作从链表的头部或者尾部添加和删除元素 这使得 list 既可以用作栈,也可以用作...:可以次性加多个 2、lrange 获取链表里面的元素 语法:lrange 链表的名称 ...
  • Java字节码结构剖析:异常

    千次阅读 2019-01-05 00:31:06
    异常实际上是Java代码的部分,编译器使用异常而不是简单的跳转命令来实现Java异常及`finally`处理机制。(:在JDK1.4.2之前的Javac编译器采用了jsr和ret指令实现`finally`语句。在JDK1.7中,已经完全禁止...
  • WORD中图、、公式自动编号及制表位、尾的应用 .图表和公式的自动编号2 二.制表位的使用3 三.目录的制作4 四.参考文献的编号和引用5 .页眉页脚的制作6 六.其他技巧7 ...
  • :未经博主同意,不得转载。  链表是另种形式的链式存储结构,它是线性链表的种变形。在线性链表中,每个结点的指针都指向它的下个结点,最后个结点的指针域为空,表示链表的结束。若使最后个结点的...
  • 的加法:union(按行合并在一起...:会把相同部分留下组数据,如需保留重复行数据,那么使用union all二、的联结:交叉联结、内联结、左联结、右联结、全联结1.交叉联结:中每行都和另的每...
  • :下三角矩阵中:i&lt;j 时 k=n(n+1)/2,是因为上三角中的元素是同个值,所以就存在矩阵的最后个位置即可。 上三角矩阵同理。
  • 、顺序元素查找 六、顺序取元素数据 七、主函数定义 1. typedef 解释 2. 链表知识点总结 、顺序定义及特点 1.顺序定义 用数组存储线性表,称作线性表的顺序存储结构或顺序映像,用这种方法...
  • 1、用户可通过【数据透视】按钮创建数据透视图。EXCEL将创建一张新的数据透视幅新的数据透视图。2、此外也可先创建数据透视...:不论采用那种方法,数据透视和数据透视图都链接在一起,其中之的改变...
  • 新微信号的话要连续登陆使用72小时后,才可以解绑手机号):这个里的使用七十二小时,不是挂后台七十二小时,要聊天七十二小时!!!有网友说不能解绑手机号了!是真的不能解绑手机号了吗?其实是他们只知道在设置...
  • 当数据库中某个数据的属性名称发生改变的时候,我们需要快速的实现变动,使得程序正常运行 二、实现方法 1.步骤 1.找到需要修改的属性,然后通过eclipse找到如下位置 2.点击replace按钮,输入需要替换的内容 3....
  • []“大”减“小”是指绝对值的大小。合并同类项合并同类项,法则不能忘,只求系数和,字母、指数不变样。去、添括号法则去括号、添括号,关键看符号,括号前面是正号,去、添括号不变号,括号前面是负号,去、添...
  • :本文非标准教程,仅是总结个人学习过程,可能存在纰漏,如有错误之处欢迎留言告知,非常感谢 来自:中国大学mooc 《Python语言程序设计》北京理工大学 嵩天、黄天羽、礼欣 维数组 维数据的表示 如果数据间...
  • 剑指offer链表翻转

    2019-04-19 10:57:48
    链表翻转有两种方式,分为迭代法和递归法两种方式可以实现,其中迭代就是从头到尾遍历遍,一直到链表尾端,而递归不同...第步首先如下图给定个链表,可以存入个数据 第二步然后自定义两个链表指针,...
  • 原标题:【乐理知识】音符与休止符时值对照(建议收藏) 线谱与简谱的音符时值对照 (:简谱在音符的后面每加一条短横线,表示增加拍的长度。)附点音符——记在音符(或休止符)右侧的小圆点,表示将这个音符...
  • 年幼儿出勤统计 月 份 在册 人数 应出勤 人数 应出勤人次数 实际 出勤 人次数 出勤率% 缺勤分析 备 病假人次 事假 人次 其他人次 月 二月 三月 四月 月 六月 七月 八月 九月
  • 创建用户空间

    2015-01-29 21:02:07
    TOUSER=TGPMS2 (:把的拥有者由FROMUSER改为TOUSER,FROMUSER和TOUSER的用户可以不同) ROWS=Y INDEXES=Y GRANTS=Y CONSTRAINTS=Y BUFFER=409600 file==/backup/ctgpc_20030623.dmp log==/backup/import...
  • 查询三、从其他中加载数据四、视图、sql执行顺序六、索引七、事务 、mysql的三大范式 原子性 字段不可在分割 唯一性 字段必须依赖于主键 冗余性 避免数据量过大 二、连联查 删除之前的...
  • :当讲InnoDB的转换为MyISAM的时,原的一切特性(事务,行锁之类的)会全部丢失,即使之后转换回原引擎,也无法恢复这些特性。 2.手动的导入与导出 利用mysqldump导出数据,再手动修改create table ...
  • newxy(新坐标)DAO类对表结构的注册过程,及结构变化...、DAO类对表结构的即时注册newxy(新坐标)的DAO类在进行数据的查询、增、删、改时都会调用注册方法,根据业务涉及到的数据库相关数据源名和表名进行注册,
  • 人工智能学院勤工助学申请夏季学期 学 号 姓 名 政治面貌 寸照片 (电子版即可) 专业 是否为家庭经济困难生 手机 邮箱 交通银行太平洋学子卡号 学生工作或 学生工作或 勤工助学经历 申请理由 空闲时间统计 时间 ...
  • :以下程序与概念均参考自《java编程思想》、《数据结构与java集合框架》、《算法导论》 目录 、集合是什么 二、基于数组实现的——ArrayList 1、类标题 2、类字段 3、构造方法 4、add()以及数组扩容 5...
  • 网页中的预定义色,使用英文单词进行颜色的表示;比如red,blue等 ...:以上种表达方式都是属于RGB色系(红,绿,蓝) RGBA:和RGB一样,只是多了个透明度,比如RGB(255,0,0,0.5)。第四个值取.
  • 、Geber文件的输出步骤: :选择需要导出的层 :所指箭头的地方都多加个零,让输出有更大的空间来容纳 总结:这就是最终的Geber文件了 二、NC Drill file的输出: 三、IPC网的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 400
精华内容 160
关键字:

五表一注