web 相关技术栈

web 相关技术栈 文章目录

web相关技术栈 笔记回顾


提示:要加油 !!!

文章目录

  • web 相关技术栈 文章目录
  • 前言
  • 一、XML 语言的学习
    • 概念
    • 语法
    • 解析
      • 对象的使用:
      • 快捷查询方式:
  • 二、JDBC
    • 1.概念
      • 获取数据库连接:
      • Statement:执行sql的对象
      • ResultSet:结果集对象,封装查询结果
      • PreparedStatement:执行sql的对象
      • 抽取JDBC工具类 : JDBCUtils
      • JDBC控制事务:
  • 三 MyBatis框架搭建
      • 1.1、什么是MyBatis
      • 1.2、持久化
      • 1.3、持久层
      • 1.4、为什么需要Mybatis
      • 2、MyBatis第一个程序
      • 2.2、问题说明
      • 3、CRUD操作
        • 3.1、namespace
        • 3.2、select
        • 思路一:直接在方法中传递参数
        • 思路二:使用万能的Map
        • 3.3、insert
        • 3.4、update
        • 3.5、delete
        • 3.6、思考题
        • 模糊查询like语句该怎么写?
        • 4、配置解析
        • 4.2、environments元素
  • SMBMS 超市管理系统
        • 登录功能实现
        • 修改密码的操作
        • Ajax
        • 简介
        • JQuery.ajax
          • 加session的过期时间
        • 用户管理实现
          • 获取用户数量
        • 页面展示(和分页)
          • 不管是什么操作都需要根据baseDao来写的
        • 获取角色的操作
        • 用户显示Servlet
        • 增删改操作
        • 删除用户
  • 文件上传
        • 注意事项
  • Spring
        • 1.1 简介
        • 1.2 优点
        • 1.3 组成
        • 1.4 拓展
          • Spring Boot与Spring Cloud
        • 2、IoC基础
        • 3.Spring 和Mybatis
        • SqlSession能干什么?
        • 整合实现一
        • Spring 和Mybatis整合之后的样子
        • 整合实现二
        • 声明式事务
        • Spring中的事务管理
  • SpringMVC
        • 1.1、什么是MVC


前言

提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、XML 语言的学习

web 相关技术栈_第1张图片

概念

  1. :Extensible Markup Language 可扩展标记语言
    • 可扩展:标签都是自定义的。

    • 功能

      • 存储数据
        1. 配置文件
        2. 在网络中传输
    • xml与html的区别

      1. xml标签都是自定义的,html标签是预定义。
      2. xml的语法严格(所以不能代替html 所以另辟蹊径 和properties (配置信息竞争)),
        html语法松散(由于浏览器的恶行竞争)
      3. xml是存储数据 (1.做配置文件(复杂的配置文件)
        2.在信息传输中用)的,
        html是展示数据
    • w3c:万维网联盟

语法

  • 基本语法:
    1. xml文档的后缀名 .xml
    2. xml 第一行 (不能有空格)必须定义为文档声明
    3. xml文档中有且仅有一个根标签
    4. 属性值必须使用引号(单双都可)引起来
    5. 标签必须 正确关闭
    6. xml 标签名称区 分大小写
    • 快速入门 (一个xml文件):

		<users>
			<user id='1'>
				<name>zhangsanname>
				<age>23age>
				<gender>malegender>
				<br/>
			user>
			
			<user id='2'>
				<name>lisiname>
				<age>24age>
				<gender>femalegender>
			user>
		users>

3.组成部分:

    • 文档声明(必须定义在第一行)
        1. 格式: //>?

          1. 格式: //>?
          2. 属性列表:
            • version:版本号,必须的属性
            • encoding:编码方式。告知解析引擎当前文档使用的字符集,默认值:ISO-8859-1 (当前的文件写的时候用什么编码就用什么解码)
            • standalone:是否独立
              • 取值:
                • yes:不依赖其他文件
                • no:依赖其他文件
        2. 指令(了解):结合css的 (现在基本做数据存储 所以和css连接使用就很少)

        3. 标签:标签名称自定义的

          • 规则:
            • 名称可以包含字母、数字以及其他的字符
            • 名称不能以数字或者标点符号开始
            • 名称不能以字母 xml(或者 XMLXml 等等)开始
            • 名称不能包含空格
        4. 属性:
          id属性值唯一 必须用 单 或者 双引 包括

        5. 文本:
          & --> & (需要转移字符 比较麻烦 用下面的方式可以直接显示)

          • CDATA区:在该区域中的数据会被原样展示
            • 格式:
            • 约束:规定xml文档的书写规则
              ​ * 作为框架(软件)的使用者(程序员):
              ​ 1. 能够在xml中引入约束文档
              ​ 2. 能够简单的读懂约束文档
  • 分类:

    1. DTD:一种简单的约束技术
    2. Schema:一种复杂的约束技术(满足了dtd的不足)
      (加入了值的筛选 内容的限定)

两种规范:

  • DTD:
    • 引入dtd文档到xml文档中
      • 内部dtd(不常用):将约束规则定义在xml文档中
      • 外部dtd:将约束的规则定义在外部的dtd文件中
      • 本地:
      • 网络:

解析

操作xml文档,将文档中的数据读取到内存中

  • 操作xml文档
    1. 解析(读取):将文档中的数据读取到内存中
    2. 写入:将内存中的数据保存到xml文档中。持久化的存储* 解析xml的方式:
    3. DOM:将标记语言文档一次性加载进内存,在内存中形成一颗dom树 (在服务器这种内存比较大的用)
    4. * 优点:操作方便,可以对文档进行CRUD的所有操作
    * 缺点:占内存
    5. SAX:逐行读取,基于事件驱动的。 (安卓种这种 小内存的设备用)
    * 优点:不占内存。
    * 缺点:只能读取,不能增删改
    • xml常见的解析器:
      1. JAXP(代码写起来不好 不同): sun公司提供的解析器,支持dom和sax两种思想
      2. DOM4J :一款非常优秀的解析器
      3. Jsoup:jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址(爬虫)、HTML文本内容。它提供了一套非常省力的API,可通过 DOM, CSS以及类似于jQuery的操作方法来取出和操作数据。
      4. PULL:Android操作系统内置的解析器,sax方式的。
    • Jsoup:jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
      • 快速入门:
        • 步骤:
          1. 导入jar包
          2. 获取Document对象
          3. 获取对应的标签Element对象
          4. 获取数据
      • 代码:
			 //2.1获取student.xml的path
	        String path = JsoupDemo1.class.getClassLoader().getResource("student.xml").getPath();
	        //2.2解析xml文档,加载文档进内存,获取dom树--->Document
	        Document document = Jsoup.parse(new File(path), "utf-8");
	        //3.获取元素对象 Element
	        Elements elements = document.getElementsByTag("name");
	
	        System.out.println(elements.size());
	        //3.1获取第一个name的Element对象
	        Element element = elements.get(0);
	        //3.2获取数据
	        String name = element.text();
	        System.out.println(name);

对象的使用:

  1. Jsoup:工具类,可以解析html或xml文档,返回Document
    * parse:解析html或xml文档,返回Document
    * parse​(File in, String charsetName):解析xml或html文件的。
    * parse​(String html):解析xml或html字符串
    * parse​(URL url, int timeoutMillis):通过网络路径获取指定的html或xml的文档对象
    2. Document:文档对象。代表内存中的dom树
    * 获取Element对象
    * getElementById​(String id):根据id属性值获取唯一的element对象
    * getElementsByTag​(String tagName):根据标签名称获取元素对象集合
    * getElementsByAttribute​(String key):根据属性名称获取元素对象集合
    * getElementsByAttributeValue​(String key, String value):根据对应的属性名和属性值获取元素对象集合
    3. Elements:元素Element对象的集合。可以当做 ArrayList来使用
    4. Element:元素对象
    1. 获取子元素对象
    * getElementById​(String id):根据id属性值获取唯一的element对象
    * getElementsByTag​(String tagName):根据标签名称获取元素对象集合
    * getElementsByAttribute​(String key):根据属性名称获取元素对象集合
    * getElementsByAttributeValue​(String key, String value):根据对应的属性名和属性值获取元素对象集合
    2. 获取属性值
    * String attr(String key):根据属性名称获取属性值
    3. 获取文本内容
    * String text():获取文本内容
    * String html():获取标签体的所有内容(包括字标签的字符串内容)
    5. Node:节点对象
    * 是Document和Element的父类

快捷查询方式:

​ 1. selector: 选择器
​ * 使用的方法:Elements select​(String cssQuery)
​ * 语法:参考Selector类中定义的语法
​ 2. XPath:XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言
​ * 使用Jsoup的Xpath需要额外导入jar包。
​ * 查询w3cshool参考手册,使用xpath的语法完成查询
​ * 代码:

//1.获取student.xml的pathString path = JsoupDemo6.class.getClassLoader().getResource("student.xml").getPath();//2.获取Document对象Document document = Jsoup.parse(new File(path), "utf-8");
​			
​			        //3.根据document对象,创建JXDocument对象JXDocument jxDocument = new JXDocument(document);
		        //4.结合xpath语法查询
		        //4.1查询所有student标签
		        List<JXNode> jxNodes = jxDocument.selN("//student");
		        for (JXNode jxNode : jxNodes) {
		            System.out.println(jxNode);
		        }
		
		        System.out.println("--------------------");
		
		        //4.2查询所有student标签下的name标签
		        List<JXNode> jxNodes2 = jxDocument.selN("//student/name");
		        for (JXNode jxNode : jxNodes2) {
		            System.out.println(jxNode);
		        }
		
		        System.out.println("--------------------");
		
		        //4.3查询student标签下带有id属性的name标签
		        List<JXNode> jxNodes3 = jxDocument.selN("//student/name[@id]");
		        for (JXNode jxNode : jxNodes3) {
		            System.out.println(jxNode);
		        }
		        System.out.println("--------------------");
		        //4.4查询student标签下带有id属性的name标签 并且id属性值为itcast
		
		        List<JXNode> jxNodes4 = jxDocument.selN("//student/name[@id='itcast']");
		        for (JXNode jxNode : jxNodes4) {
		            System.out.println(jxNode);
		        }

二、JDBC

1.概念

jdbc的本质 为什么需要jdbc 都是接口 :

  1. 概念:Java DataBase Connectivity Java 数据库连接, Java语言操作数据库
    • JDBC本质:其实是官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

快速入门:
* 步骤:
1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
1.复制mysql-connector-java-5.1.37-bin.jar到项目的libs目录下
2.右键–>Add As Library (如果是maven 需要导入依赖 不用导入lib )
2. 注册驱动
3. 获取数据库连接对象 Connection
4. 定义sql
5. 获取执行sql语句的对象 Statement
6. 执行sql,接受返回结果
7. 处理结果
8. 释放资源
2.代码实现

//1. 导入驱动jar包
        //2.注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //3.获取数据库连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db3", "root", "root");
        //4.定义sql语句
        String sql = "update account set balance = 500 where id = 1";
        //5.获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        //6.执行sql
        int count = stmt.executeUpdate(sql);
        //7.处理结果
        System.out.println(count);
        //8.释放资源
        stmt.close();
        conn.close();

详解各个对象:
1. DriverManager:驱动管理对象
* 功能:
1. 注册驱动:告诉程序该使用哪一个数据库驱动jar
static void registerDriver(Driver driver) :注册与给定的驱动程序 DriverManager 。
写代码使用: Class.forName(“com.mysql.jdbc.Driver”);
通过查看源码发现:在com.mysql.jdbc.Driver类中存在 静态代码块
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException(“Can’t register driver!”);
}
}

			注意:mysql 5之后的驱动jar包可以省略注册驱动的步骤。

获取数据库连接:

  • 方法:static Connection getConnection(String url, String user, String password)
    * 参数:
    * url:指定连接的路径
    * 语法:jdbc:mysql://ip地址(域名):端口号/数据库名称
    * 例子:jdbc:mysql://localhost:3306/db3
    * 细节:如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称
    * user:用户名
    * password:密码
    1. Connection:数据库连接对象
      1. 功能:
        1. 获取执行sql 的对象
          • Statement createStatement()
          • PreparedStatement prepareStatement(String sql)
        2. 管理事务:
          • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
          • 提交事务:commit()
          • 回滚事务:rollback()

Statement:执行sql的对象

  1. 执行sql
    1. boolean execute(String sql) :可以执行任意的 sql (了解)
    2. int executeUpdate(String sql) :执行DML(insert、update、delete)语句、DDL(create,alter、drop)语句
    * 返回值:影响的行数,可以通过这个影响的行数判断DML语句是否执行成功 返回值>0的则执行成功,反之,则失败。
    3. ResultSet executeQuery(String sql) :执行DQL(select)语句 返回的是结果集
    2. 练习:
    1. account表 添加一条记录
    2. account表 修改记录
    3. account表 删除一条记录
Statement stmt = null;
		        Connection conn = null;
		        try {
		            //1. 注册驱动
		            Class.forName("com.mysql.jdbc.Driver");
		            //2. 定义sql
		            String sql = "insert into account values(null,'王五',3000)";
		            //3.获取Connection对象
		            conn = DriverManager.getConnection("jdbc:mysql:///db3", "root", "root");
		            //4.获取执行sql的对象 Statement
		            stmt = conn.createStatement();
		            //5.执行sql
		            int count = stmt.executeUpdate(sql);//影响的行数
		            //6.处理结果
		            System.out.println(count);
		            if(count > 0){
		                System.out.println("添加成功!");
		            }else{
		                System.out.println("添加失败!");
		            }
		        } catch (ClassNotFoundException e) {
		            e.printStackTrace();
		        } catch (SQLException e) {
		            e.printStackTrace();
		        }finally {
		            //stmt.close();
		            //7. 释放资源
		            //避免空指针异常
		            if(stmt != null){
		                try {
		                    stmt.close();
		                } catch (SQLException e) {
		                    e.printStackTrace();
		                }
		            }
		            if(conn != null){
		                try {
		                    conn.close();
		                } catch (SQLException e) {
		                    e.printStackTrace();
		                }
		            }
		        }

ResultSet:结果集对象,封装查询结果

  • boolean next(): 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回false,如果不是则返回true
    * getXxx(参数):获取数据
    * Xxx:代表数据类型 如: int getInt() , String getString()
    * 参数:
    1. int:代表列的编号,从1开始 如: getString(1)
    2. String:代表列名称。 如: getDouble(“balance”)
    * 注意:
    * 使用步骤:
    1. 游标向下移动一行
    2. 判断是否有数据
    3. 获取数据
			   //循环判断游标是否是最后一行末尾。
	            while(rs.next()){
	                //获取数据
	                //6.2 获取数据
	                int id = rs.getInt(1);
	                String name = rs.getString("name");
	                double balance = rs.getDouble(3);
	
	                System.out.println(id + "---" + name + "---" + balance);
	            }

PreparedStatement:执行sql的对象

  1. SQL注入问题:在拼接sql时,有一些sql的特殊关键字参与字符串的拼接。会造成安全性问题
    1. 输入用户随便,输入密码:a’ or ‘a’ = 'a
    2. sql:select * from user where username = ‘fhdsjkf’ and password = ‘a’ or ‘a’ = ‘a’
    2. 解决sql注入问题:使用PreparedStatement对象来解决
    3. 预编译的SQL:参数使用?作为占位符
    4. 步骤:
    1. 导入驱动jar包 mysql-connector-java-5.1.37-bin.jar
    2. 注册驱动
    3. 获取数据库连接对象 Connection
    4. 定义sql
    * 注意:sql的参数使用?作为占位符。 如:select * from user where username = ? and password = ?;
    5. 获取执行sql语句的对象 PreparedStatement Connection.prepareStatement(String sql)
    6. 给?赋值:
    * 方法: setXxx(参数1,参数2)
    * 参数1:?的位置编号 从1 开始
    * 参数2:?的值
    7. 执行sql,接受返回结果,不需要传递sql语句
    8. 处理结果
    9. 释放资源
    5. 注意:后期都会使用PreparedStatement来完成增删改查的所有操作
    1. 可以防止SQL注入
    2. 效率更高

抽取JDBC工具类 : JDBCUtils

  • 目的:简化书写
  • 分析:
    1. 注册驱动也抽取
    2. 抽取一个方法获取连接对象
      • 需求:不想传递参数(麻烦),还得保证工具类的通用性。
      • 解决方法:配置文件
        jdbc.properties
        url=
        user=
        password=
    3. 抽取一个方法释放资源
      代码实现:
public class JDBCUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    /**
     * 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
     */
    static{
        //读取资源文件,获取值。
        try {
            //1. 创建Properties集合类。
            Properties pro = new Properties();

            //获取src路径下的文件的方式--->ClassLoader 类加载器
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            URL res  = classLoader.getResource("jdbc.properties");
            String path = res.getPath();
            System.out.println(path);///D:/IdeaProjects/itcast/out/production/day04_jdbc/jdbc.properties
            //2. 加载文件
           // pro.load(new FileReader("D:\\IdeaProjects\\itcast\\day04_jdbc\\src\\jdbc.properties"));
            pro.load(new FileReader(path));

            //3. 获取数据,赋值
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");
            //4. 注册驱动
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void close(Statement stmt,Connection conn){
        if( stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if( conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

使用 工具类

   /**
​	     * 获取连接
​	     * @return 连接对象
​	     */public static Connection getConnection() throws SQLException {return DriverManager.getConnection(url, user, password);
	    }

测试

 /**
​				     * 登录方法
​				     */public boolean login(String username ,String password){if(username == null || password == null){return false;}//连接数据库判断是否登录成功Connection conn = null;Statement stmt =  null;ResultSet rs = null;//1.获取连接try {
​				            conn =  JDBCUtils.getConnection();//2.定义sqlString sql = "select * from user where username = '"+username+"' and password = '"+password+"' ";//3.获取执行sql的对象
​				            stmt = conn.createStatement();//4.执行查询
​				            rs = stmt.executeQuery(sql);//5.判断/* if(rs.next()){//如果有下一行,则返回true
​				                return true;
​				            }else{
​				                return false;
​				            }*/return rs.next();//如果有下一行,则返回true} catch (SQLException e) {
				            e.printStackTrace();
				        }finally {
				            JDBCUtils.close(rs,stmt,conn);
				        }

​				
​				        return false;}}

JDBC控制事务:

  1. 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
  2. 操作:
    1. 开启事务
    2. 提交事务
    3. 回滚事务
  3. 使用Connection对象来管理事务
    • 开启事务:setAutoCommit(boolean autoCommit) :调用该方法设置参数为false,即开启事务
      • 在执行sql之前开启事务
    • 提交事务:commit()
      • 当所有sql都执行完提交事务
    • 回滚事务:rollback()
      • 在catch中回滚事务
	public class JDBCDemo10 {

	    public static void main(String[] args) {
	        Connection conn = null;
	        PreparedStatement pstmt1 = null;
	        PreparedStatement pstmt2 = null;
	
	        try {
	            //1.获取连接
	            conn = JDBCUtils.getConnection();
	            //开启事务
	            conn.setAutoCommit(false);
	
	            //2.定义sql
	            //2.1 张三 - 500
	            String sql1 = "update account set balance = balance - ? where id = ?";
	            //2.2 李四 + 500
	            String sql2 = "update account set balance = balance + ? where id = ?";
	            //3.获取执行sql对象
	            pstmt1 = conn.prepareStatement(sql1);
	            pstmt2 = conn.prepareStatement(sql2);
	            //4. 设置参数
	            pstmt1.setDouble(1,500);
	            pstmt1.setInt(2,1);
	
	            pstmt2.setDouble(1,500);
	            pstmt2.setInt(2,2);
	            //5.执行sql
	            pstmt1.executeUpdate();
	            // 手动制造异常
	            int i = 3/0;
	
	            pstmt2.executeUpdate();
	            //提交事务
	            conn.commit();
	        } catch (Exception e) {
	            //事务回滚
	            try {
	                if(conn != null) {
	                    conn.rollback();
	                }
	            } catch (SQLException e1) {
	                e1.printStackTrace();
	            }
	            e.printStackTrace();
	        }finally {
	            JDBCUtils.close(pstmt1,conn);
	            JDBCUtils.close(pstmt2,null);
	        }
   }
}

三 MyBatis框架搭建

环境说明:
jdk 8 +
MySQL 5.7.19
maven-3.6.0
IDEA
学习前需要掌握:
JDBC
MySQL
Java 基础
Maven
Junit

1.1、什么是MyBatis

(就是简化jdbc 操作的框架 )
MyBatis 是一款优秀的持久层框架
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程
MyBatis 可以使用简单的 XML注解来配置和映射原生信息,将接口和 Java 的 实体类 【Plain Old Java Objects,普通的 Java对象】映射成数据库中的记录。
MyBatis 本是apache的一个开源项目ibatis, 2010年这个项目由apache 迁移到了google code,并且改名为MyBatis 。
2013年11月迁移到Github .
Mybatis官方文档 : link.
GitHub : https://github.com/mybatis/mybatis-3

1.2、持久化

持久化是将程序数据在持久状态和瞬时状态间转换的机制。
即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用
是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
JDBC就是一种持久化机制。文件IO也是一种持久化机制。
在生活中 : 将鲜肉冷藏,吃的时候再解冻的方法也是。将水果做成罐头的方法也是。
为什么需要持久化服务呢?那是由于内存本身的缺陷引起的
内存断电后数据会丢失,但有一些对象是无论如何都不能丢失的,比如银行账号等,遗憾的 是,人们还无法保证内存永不掉电。
内存过于昂贵,与硬盘、光盘等外存相比,内存的价格要高2~3个数量级,而且维持成本也高,至少需要一直供电吧。所以即使对象不需要永久保存,也会因为内存的容量限制不能一直 呆在内存中,需要持久化来缓存到外存

1.3、持久层

什么是持久层?
完成持久化工作的代码块 . ----> dao层 【DAO (Data Access Object) 数据访问对象】
大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。
不过这里有一个字需要特别强调,也就是所谓的“层”。对于应用系统而言,数据持久功能大多是必不可少的组成部分。也就是说,我们的系统中,已经天然的具备了“持久层”概念?也许是,但也许实际情况并非如此。之所以要独立出一个“持久层”的概念,而不是“持久模块”,“持久单元”,也就意味着,我们的系统架构中,应该有一个相对独立的逻辑层面,专著于数据持久化逻辑的实现.
与系统其他部分相对而言,这个层面应该具有一个较为清晰和严格的逻辑边界。 【说白了就是用来操作数据库存在的!】

1.4、为什么需要Mybatis

Mybatis就是帮助程序猿将数据存入数据库中 , 和从数据库中取数据 .
传统的jdbc操作 , 有很多重复代码块 .比如 : 数据取出时的封装 , 数据库的建立连接等等… , 通过框架可以减少重复代码,提高开发效率 .MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射所有的事情,不用Mybatis依旧可以做到,只是用了它,所有实现会更加简单!技术没有高低之分,只有使用这个技术的人有高低之别
== MyBatis的优点 ==
简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件就可以了,易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
提供xml标签,支持编写动态sql。

生态 : 最重要的一点,使用的人多!公司需要

2、MyBatis第一个程序

思路流程:搭建环境–>导入Mybatis—>编写代码—>测试

  1. 搭建实验数据库
CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(30) DEFAULT NULL,
`pwd` varchar(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `user`(`id`,`name`,`pwd`) values (1,'狂神','123456'),(2,'张
三','abcdef'),(3,'李四','987654');
  1. 导入MyBatis相关 jar 包
    GitHub上找 (下面就是导入依赖 修改配置问价)
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
  1. 编写MyBatis核心配置文件
    查看帮助文档

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/mybatis?
useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/kuang/dao"/> //保证userMapper接口和userMapper接口是一个包 同名字
mappers>
configuration>
  1. 编写MyBatis工具类
    查看帮助文档
	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 java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml"; //获取配置文件 来连接数据库
InputStream inputStream =
Resources.getResourceAsStream(resource); // 用流对象进行传输
sqlSessionFactory = new
SqlSessionFactoryBuilder().build(inputStream); // 获取工厂 
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();//构建数据库操作对象
}
}
  1. 创建实体类
public class User {
private int id; //id
private String name; //姓名
private String pwd; //密码
//构造,有参,无参
//set/get
//toString()
}
  1. 编写Mapper接口类
import com.kuang.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUser();
}
  1. 编写Mapper.xml配置文件
    namespace 十分重要,不能写错
?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="com.kuang.dao.UserMapper"> //namespace是接口的地址
<select id="selectUser" resultType="com.kuang.pojo.User"> //resultType是返回值类型
select * from user //是sql语言
</select>
</mapper>
  1. 编写测试类
    Junit 包测试
public class MyTest {
@Test
public void selectUser() {
SqlSession session = MybatisUtils.getSession();//得到数据库操作对象
//方法一:
//List users =
session.selectList("com.kuang.mapper.UserMapper.selectUser");//
//方法二:
UserMapper mapper = session.getMapper(UserMapper.class);//
List<User> users = mapper.selectUser();
for (User user: users){
System.out.println(user);
}
session.close();
}
}
  1. 运行测试

2.2、问题说明

可能出现问题说明:Maven静态资源过滤问题

<resources>
<resource>
<directory>src/main/javadirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
<resource>
<directory>src/main/resourcesdirectory>
<includes>
<include>**/*.propertiesinclude>
<include>**/*.xmlinclude>
includes>
<filtering>falsefiltering>
resource>
resources>

3、CRUD操作

3.1、namespace
  1. 将上面案例中的UserMapper接口改名为 UserDao;
  2. 将UserMapper.xml中的namespace改为为UserDao的路径 .
  3. 再次测试
    结论:
    配置文件中namespace中的名称为对应Mapper接口或者Dao接口的完整包名,必须一致!
3.2、select

select标签是mybatis中最常用的标签之一
select语句有很多属性可以详细配置每一条SQL语句
id
命名空间中唯一的标识符
接口中的方法名与映射文件中的SQL语句ID 一一对应
parameterType
传入SQL语句的参数类型 。【万能的Map,可以多尝试使用】
resultType
SQL语句返回值类型。【完整的类名或者别名】
需求:根据id查询用户

  1. 在UserMapper中添加对应方法
public interface UserMapper {
//查询全部用户
List<User> selectUser();
//根据id查询用户
User selectUserById(int id);
}
  1. 在UserMapper.xml中添加Select语句 (注意 id 要和接口种的方法名称一一对应)
<select id="selectUserById" resultType="com.kuang.pojo.User">
select * from user where id = #{id}
select>
  1. 测试类中测试
@Test
public void tsetSelectUserById() {
SqlSession session = MybatisUtils.getSession(); //获取SqlSession连接
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
System.out.println(user);
session.close();
}

课堂练习:根据 密码 和 名字 查询用户

思路一:直接在方法中传递参数
  1. 在接口方法的参数前加 @Param属性
  2. Sql语句编写的时候,直接取@Param中设置的值即可,不需要单独设置参数类型
//通过密码和名字查询用户
在 mapper的接口中声明 方法:
User selectUserByNP(@Param("username") String username,@Param("pwd") String
pwd);Mapper.xml中写 用接口中传递的参数
<select id="selectUserByNP" resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
</select>
思路二:使用万能的Map
  1. 在接口方法中,参数直接传递Map;
User selectUserByNP2(Map<String,Object> map);
  1. 编写sql语句的时候,需要传递参数类型,参数类型为map
<select id="selectUserByNP2" parameterType="map"
resultType="com.kuang.pojo.User">
select * from user where name = #{username} and pwd = #{pwd}
select>
  1. 在使用方法的时候,Map的 key 为 sql中取的值即可,没有顺序要求!
Map<String, Object> map = new HashMap<String, Object>();
map.put("username","小明");
map.put("pwd","123456");
User user = mapper.selectUserByNP2(map);

总结:
如果参数过多,我们可以考虑直接使用Map实现,如果参数比较少,直接传递参数即可

3.3、insert

我们一般使用insert标签进行插入操作,它的配置和select标签差不多!
需求:给数据库增加一个用户

  1. 在UserMapper接口中添加对应的方法
/添加一个用户
int addUser(User user);
  1. 在UserMapper.xml中添加insert语句
<insert id="addUser" parameterType="com.kuang.pojo.User">
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>
  1. 测试
@Test
public void testAddUser() {
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = new User(5,"王五","zxcvbn");
int i = mapper.addUser(user);
System.out.println(i);
session.commit(); //提交事务,重点!不写的话不会提交到数据库
session.close();
}

注意点:增、删、 改操作需要提交事务!

3.4、update

我们一般使用update标签进行更新操作,它的配置和select标签差不多!
需求:修改用户的信息

  1. 同理,编写接口方法
//修改一个用户
int updateUser(User user);
  1. 编写对应的配置文件SQL
<update id="updateUser" parameterType="com.kuang.pojo.User">
update user set name=#{name},pwd=#{pwd} where id = #{id}
</update>
  1. 测试
@Test
public void testUpdateUser() {
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectUserById(1);
user.setPwd("asdfgh");
int i = mapper.updateUser(user);
System.out.println(i);
session.commit(); //提交事务,重点!不写的话不会提交到数据库
session.close();
}
3.5、delete

我们一般使用delete标签进行删除操作,它的配置和select标签差不多!
需求:根据id删除一个用户

  1. 同理,编写接口方法
/根据id删除用户
int deleteUser(int id);
  1. 编写对应的配置文件SQL
<delete id="deleteUser" parameterType="int">
delete from user where id = #{id}
delete>
@Test
public void testDeleteUser() {
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int i = mapper.deleteUser(5);
System.out.println(i);
session.commit(); //提交事务,重点!不写的话不会提交到数据库
session.close();
}

小结:
所有的增删改操作都需要提交事务!
接口所有的普通参数,尽量都写上@Param参数,尤其是多个参数时,必须写上!
有时候根据业务的需求,可以考虑使用map传递参数!
为了规范操作,在SQL的配置文件中,我们尽量将Parameter参数和resultType都写上!

3.6、思考题
模糊查询like语句该怎么写?

第1种:在Java代码中添加sql通配符。

string wildcardname =%smi%;
list<name> names = mapper.selectlike(wildcardname);
在 mapper.xml文件中配置
<select id=”selectlike”>
select * from foo where bar like #{value}
</select>

第2种:在sql语句中拼接通配符,会引起sql注入

string wildcardname = “smi”;
list<name> names = mapper.selectlike(wildcardname);
<select id=”selectlike”>
select * from foo where bar like "%"#{value}"%"
</select>
4、配置解析

4.1、核心配置文件
mybatis-config.xml 系统核心配置文件
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
能配置的内容如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

我们可以阅读 mybatis-config.xml 上面的dtd(就是在xml 笔记中提及的约束文档)的头文件!【演示】

4.2、environments元素
<environments default="development">
<environment id="development">
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>

配置MyBatis的多套运行环境,将SQL映射到多个不同的数据库上,必须指定其中一个为默认运行
环境(通过default指定)
子元素节点:environment
具体的一套环境,通过设置id进行区别,id保证唯一!
子元素节点:transactionManager - [ 事务管理器 ]


<transactionManager type="[ JDBC | MANAGED ]"/>

详情:点击查看官方文档
这两种事务管理器类型都不需要设置任何属性。
子元素节点:数据源(dataSource)
dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
数据源是必须配置的。
有三种内建的数据源类型
type="[UNPOOLED|POOLED|JNDI]")
unpooled: 这个数据源的实现只是每次被请求时打开和关闭连接。
pooled: 这种数据源的实现利用**“池**”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。
数据源也有很多第三方的实现,比如dbcp,c3p0,druid等等…

SMBMS 超市管理系统

  1. 先利用maven 来创建项目 记得用模板创建
  2. 导入依赖包
<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/maven-v4_0_0.xsd">

  <modelVersion>4.0.0modelVersion>
  <packaging>warpackaging>

  <name>smbmsname>
  <groupId>com.liubingroupId>
  <artifactId>smbmsartifactId>
  <version>1.0-SNAPSHOTversion>
  <dependencies>
    <dependency>
      <groupId>javax.servletgroupId>
      <artifactId>servlet-apiartifactId>
      <version>2.5version>
    dependency>
    <dependency>
      <groupId>javax.servlet.jspgroupId>
      <artifactId>javax.servlet.jsp-apiartifactId>
      <version>2.3.1version>
    dependency>
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <version>8.0.11version>
    dependency>
    <dependency>
      <groupId>javax.servlet.jsp.jstlgroupId>
      <artifactId>jstl-apiartifactId>
      <version>1.2version>
    dependency>
    <dependency>
      <groupId>taglibsgroupId>
      <artifactId>standardartifactId>
      <version>1.1.2version>
    dependency>
  dependencies>

project>
  1. 测试项目是否可以跑起来
  2. 创建项目结构
    web 相关技术栈_第2张图片
    5.编写实体类 (和数据库进行映射)
    orm映射 : 表–>类映射
    6.编写基础公共类
  • 数据库配置文件
driver=com.mysql.jdbc.Driver
#在和mysql传递数据的过程中,使用unicode编码格式,并且字符集设置为utf-8
url=jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8
user=root
password=19182030
  • 编写数据库公共类(就是连接数据库 操作数据库的类)
package com.liubin.dao;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

    /**
     * 操作数据库的基类--静态类
     * @author Administrator
     *
     */
public class BaseDao {

        static{//静态代码块,在类加载的时候执行
            init();
        }

        private static String driver;
        private static String url;
        private static String user;
        private static String password;

        //初始化连接参数,从配置文件里获得
        public static void init(){
            Properties params=new Properties();// 创建 数据库配置对象 
            String configFile = "database.properties"; // 文件名称
            InputStream is=BaseDao.class.getClassLoader().getResourceAsStream(configFile); //获取数据库配置文件的流
            try {
                params.load(is);
            } catch (IOException e) {
                e.printStackTrace();
            }
            driver=params.getProperty("driver");
            url=params.getProperty("url");
            user=params.getProperty("user");
            password=params.getProperty("password"); //取出配置文件的内容 
            System.out.println(user+password);

        }
        
        /**
         * 获取数据库连接
         * @return
         */
        public static Connection getConnection(){ //连接数据库
            Connection connection = null;
            try {
                Class.forName(driver);
                connection = DriverManager.getConnection(url, user, password);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return connection;
        }
        /**
         * 查询操作
         * @param connection
         * @param pstm
         * @param rs
         * @param sql
         * @param params
         * @return
         */
        public static ResultSet execute(Connection connection, PreparedStatement pstm, ResultSet rs,
                                        String sql, Object[] params) throws Exception{
            pstm = connection.prepareStatement(sql);
            for(int i = 0; i < params.length; i++){
                pstm.setObject(i+1, params[i]);//setObject 从下表 一开始  然而数组是0开始的
            }//遍历参数
            rs = pstm.executeQuery(); //查询 返回参数对象
            return rs;//返回参数对象
        }
        /**
         * 更新操作
         * @param connection
         * @param pstm
         * @param sql
         * @param params
         * @return
         * @throws Exception
         */
        public static int execute(Connection connection,PreparedStatement pstm,
                                  String sql,Object[] params) throws Exception{
            int updateRows = 0;
            pstm = connection.prepareStatement(sql);
            for(int i = 0; i < params.length; i++){
                pstm.setObject(i+1, params[i]);
            }
            updateRows = pstm.executeUpdate();
            return updateRows;
        }

        /**
         * 释放资源
         * @param connection
         * @param pstm
         * @param rs
         * @return
         */
        public static boolean closeResource(Connection connection,PreparedStatement pstm,ResultSet rs){
            boolean flag = true;
            if(rs != null){
                try {
                    rs.close();
                    rs = null;//GC回收
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    flag = false;
                }
            }
            if(pstm != null){
                try {
                    pstm.close();
                    pstm = null;//GC回收
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    flag = false;
                }
            }
            if(connection != null){
                try {
                    connection.close();
                    connection = null;//GC回收
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                    flag = false;
                }
            }

            return flag;
        }

    }
登录功能实现
  1. 配置前端页面
  2. 设置首页 (欢迎页面)
<welcome-file-list>
    <welcome-file>login.jspwelcome-file>
welcome-file-list>

3.编写Dao层 用户登录到接口

public interface UserDao {
    //得到要登录的用户
    public User getLoginUser(Connection connection,String userCode) throws Exception;
}

4.编写dao层接口的实现类

package com.liubin.dao.user;

import com.liubin.dao.BaseDao;
import com.liubin.pojo.User;
import sun.util.resources.cldr.chr.CalendarData_chr_US;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserDaoImpl implements UserDao {
    @Override
    public User getLoginUser(Connection connection, String userCode) throws Exception {
        PreparedStatement pstm = null;
        ResultSet rs = null;
        User _user=null;
        if (connection != null) {
            String sql = "select * from smbms_user where userCode=?";
            Object[] params = {userCode};
                BaseDao.execute(connection, pstm, rs, sql, params);
                if(rs.next()){
                    _user = new User();
                    _user.setId(rs.getInt("id"));
                    _user.setUserCode(rs.getString("userCode"));
                    _user.setUserName(rs.getString("userName"));
                    _user.setGender(rs.getInt("gender"));
                    _user.setBirthday(rs.getDate("birthday"));
                    _user.setPhone(rs.getString("phone"));
                    _user.setUserRole(rs.getInt("userRole"));
                    _user.setUserRoleName(rs.getString("userRoleName"));
                    //userList.add(_user);
                }
                BaseDao.closeResource(null,pstm,rs);

        }

        return _user;
    }
}

4.业务层(service)的接口

public User login(String userCode, String userPassword);

5.业务层(service) 实现类 操作dao就可以了

public User login(String userCode, String userPassword) {
		// TODO Auto-generated method stub
		Connection connection = null;
		User user = null;
		try {
			connection = BaseDao.getConnection();
			user = userDao.getLoginUser(connection, userCode);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			BaseDao.closeResource(connection, null, null);
		}
		
		//匹配密码
		if(null != user){
			if(!user.getUserPassword().equals(userPassword))
				user = null;
		}
		
		return user;
	}

6.编写servlet实现类

package cn.smbms.servlet.user;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.smbms.tools.Constants;

public class LogoutServlet extends HttpServlet {

	public LogoutServlet() {
		super();
	}

	public void destroy() {
		super.destroy();
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//清除session
		request.getSession().removeAttribute(Constants.USER_SESSION);
		response.sendRedirect(request.getContextPath()+"/login.jsp");
	}

	public void init() throws ServletException {

	}

}

7.注册服务

<servlet>
    <description>This is the description of my J2EE componentdescription>
    <display-name>This is the display name of my J2EE componentdisplay-name>
    <servlet-name>LoginServletservlet-name>
    <servlet-class>cn.smbms.servlet.user.LoginServletservlet-class>
  servlet>
  <servlet-mapping>
    <servlet-name>LoginServletservlet-name>
    <url-pattern>/login.dourl-pattern>
  servlet-mapping>

8.编写前端页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>系统登录 - 超市订单管理系统</title>
    <link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath }/css/style.css" />
    <script type="text/javascript">
	/* if(top.location!=self.location){
	      top.location=self.location;
	 } */
    </script>
</head>
<body class="login_bg">
    <section class="loginBox">
        <header class="loginHeader">
            <h1>超市订单管理系统</h1>
        </header>
        <section class="loginCont">
	        <form class="loginForm" action="${pageContext.request.contextPath }/login.do"  name="actionForm" id="actionForm"  method="post" >
				<div class="info">${error }</div>
				<div class="inputbox">
                    <label for="user">用户名:</label>
					<input type="text" class="input-text" id="userCode" name="userCode" placeholder="请输入用户名" required/>
				</div>	
				<div class="inputbox">
                    <label for="mima">密码:</label>
                    <input type="password" id="userPassword" name="userPassword" placeholder="请输入密码" required/>
                </div>	
				<div class="subBtn">
					
                    <input type="submit" value="登录"/>
                    <input type="reset" value="重置"/>
                </div>	
			</form>
        </section>
    </section>
</body>
</html>

修改密码的操作

1.些项目 一定要从底层向上写而不是 要什么些什么
要从 dao接口 到dao实体类 到 service接口 到 service 实现类 到 servlet 类 对接前端
2. 编写dao接口

public int updatePwd(Connection connection, int id, String pwd)throws Exception;

3.Userdao 实现类

	public int updatePwd(Connection connection, int id, String pwd)
			throws Exception {
		// TODO Auto-generated method stub
		int flag = 0;
		PreparedStatement pstm = null;
		if(connection != null){
			String sql = "update smbms_user set userPassword= ? where id = ?";
			Object[] params = {pwd,id};
			flag = BaseDao.execute(connection, pstm, sql, params);
			BaseDao.closeResource(null, pstm, null);
		}
		return flag;
	}

4.UserService接口

	public boolean updatePwd(int id, String pwd);

5.实现UserService实现类

	@Override
	public boolean updatePwd(int id, String pwd) {
		boolean flag = false;
		Connection connection = null;
		try{
			connection = BaseDao.getConnection();
			if(userDao.updatePwd(connection,id,pwd) > 0)
				flag = true;
		}catch (Exception e) {
			e.printStackTrace();
		}finally{
			BaseDao.closeResource(connection, null, null);
		}
		return flag;
	}

6.编写UserServlet实现类

private void updatePwd(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		Object o = request.getSession().getAttribute(Constants.USER_SESSION);
		String newpassword = request.getParameter("newpassword");
		boolean flag = false;
		if(o != null && !StringUtils.isNullOrEmpty(newpassword)){
			UserService userService = new UserServiceImpl();
			flag = userService.updatePwd(((User)o).getId(),newpassword);
			if(flag){
				request.setAttribute(Constants.SYS_MESSAGE, "修改密码成功,请退出并使用新密码重新登录!");
				request.getSession().removeAttribute(Constants.USER_SESSION);//session注销
			}else{
				request.setAttribute(Constants.SYS_MESSAGE, "修改密码失败!");
			}
		}else{
			request.setAttribute(Constants.SYS_MESSAGE, "修改密码失败!");
		}
		request.getRequestDispatcher("pwdmodify.jsp").forward(request, response);
	}

7.记得实现复用 需要提出方法

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		String method = request.getParameter("method");
		
		System.out.println("method----> " + method);
		
		if(method != null && method.equals("add")){
			//增加操作
			this.add(request, response);
		}else if(method != null && method.equals("query")){
			this.query(request, response);
		}else if(method != null && method.equals("getrolelist")){
			this.getRoleList(request, response);
		}else if(method != null && method.equals("ucexist")){
			this.userCodeExist(request, response);
		}else if(method != null && method.equals("deluser")){
			this.delUser(request, response);
		}else if(method != null && method.equals("view")){
			this.getUserById(request, response,"userview.jsp");
		}else if(method != null && method.equals("modify")){
			this.getUserById(request, response,"usermodify.jsp");
		}else if(method != null && method.equals("modifyexe")){
			this.modify(request, response);
		}else if(method != null && method.equals("pwdmodify")){
			this.getPwdByUserId(request, response);
		}else if(method != null && method.equals("savepwd")){
			this.updatePwd(request, response);
		}
		
	}

8.注册服务 链接前端 测试

Ajax
简介

AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。

Ajax 不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术

在 2005 年,Google 通过其 Google Suggest 使 AJAX 变得流行起来。Google Suggest能够自动帮你完成搜索单词。

Google Suggest 使用 AJAX 创造出动态性极强的 web 界面:当您在谷歌的搜索框输入关键字时,JavaScript 会把这些字符发送到服务器,然后服务器会返回一个搜索建议的列表

就和国内百度的搜索框一样!

传统的网页(即不用ajax技术的网页),想要更新内容或者提交一个表单,都需要重新加载整个网页。

使用ajax技术的网页,通过在后台服务器进行少量的数据交换,就可以实现异步局部更新。

使用Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。
B/S : 未来的主流并且会爆发时的持续增长
产品连: h5(手机端)+ 网页 + 客户端 + 手机端 (andriod + ios)+小程序

JQuery.ajax

纯JS原生实现Ajax我们不去讲解这里,直接使用jquery提供的,方便学习和使用,避免重复造轮子,有兴趣的同学可以去了解下JS原生XMLHttpRequest !

Ajax的核心是XMLHttpRequest对象(XHR)。XHR为向服务器发送请求和解析服务器响应提供了接口。能够以异步方式从服务器获取新数据。

jQuery 提供多个与 AJAX 有关的方法。

通过 jQuery AJAX 方法,您能够使用 HTTP Get 和 HTTP Post 从远程服务器上请求文本、HTML、XML 或 JSON – 同时您能够把这些外部数据直接载入网页的被选元素中。

jQuery 不是生产者,而是大自然搬运工。

jQuery Ajax本质就是 XMLHttpRequest,对他进行了封装,方便调用

jQuery.ajax(...)
      部分参数:
            url:请求地址
            type:请求方式,GET、POST(1.9.0之后用method)
        headers:请求头
            data:要发送的数据
    contentType:即将发送信息至服务器的内容编码类型(默认: "application/x-www-form-urlencoded; charset=UTF-8")
          async:是否异步
        timeout:设置请求超时时间(毫秒)
      beforeSend:发送请求前执行的函数(全局)
        complete:完成之后执行的回调函数(全局)
        success:成功之后执行的回调函数(全局)
          error:失败之后执行的回调函数(全局)
        accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型
        dataType:将服务器端返回的数据转换成指定类型
          "xml": 将服务器端返回的内容转换成xml格式
          "text": 将服务器端返回的内容转换成普通文本格式
          "html": 将服务器端返回的内容转换成普通文本格式,在插入DOM中时,如果包含JavaScript标签,则会尝试去执行。
        "script": 尝试将返回值当作JavaScript去执行,然后再将服务器端返回的内容转换成普通文本格式
          "json": 将服务器端返回的内容转换成相应的JavaScript对象
        "jsonp": JSONP 格式使用 JSONP 形式调用函数时,如 "myurl?callback=?" jQuery 将自动替换 ? 为正确的函数名,以执行回调函数

导入json(阿里巴巴) 依赖:


<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
    <version>1.2.79version>
dependency>

加session的过期时间
用户管理实现

1.导入 分页的工具

package cn.smbms.tools;

public class PageSupport {
	//当前页码-来自于用户输入
	private int currentPageNo = 1;
	
	//总数量(表)
	private int totalCount = 0;
	
	//页面容量
	private int pageSize = 0;
	
	//总页数-totalCount/pageSize(+1)
	private int totalPageCount = 1;

	public int getCurrentPageNo() {
		return currentPageNo;
	}

	public void setCurrentPageNo(int currentPageNo) {
		if(currentPageNo > 0){
			this.currentPageNo = currentPageNo;
		}
	}

	public int getTotalCount() {
		return totalCount;
	}

	public void setTotalCount(int totalCount) {
		if(totalCount > 0){
			this.totalCount = totalCount;
			//设置总页数
			this.setTotalPageCountByRs();
		}
	}
	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		if(pageSize > 0){
			this.pageSize = pageSize;
		}
	}

	public int getTotalPageCount() {
		return totalPageCount;
	}

	public void setTotalPageCount(int totalPageCount) {
		this.totalPageCount = totalPageCount;
	}
	
	public void setTotalPageCountByRs(){
		if(this.totalCount % this.pageSize == 0){
			this.totalPageCount = this.totalCount / this.pageSize;
		}else if(this.totalCount % this.pageSize > 0){
			this.totalPageCount = this.totalCount / this.pageSize + 1;
		}else{
			this.totalPageCount = 0;
		}
	}
	
}

2.用户列表页面导入
用户列表

获取用户数量

1.userdao

public int getUserCount(Connection connection, String userName, int userRole)throws Exception;

2.Userdaoimpl

p@Override
	public int getUserCount(Connection connection, String userName, int userRole) 
			throws Exception {
		// TODO Auto-generated method stub
		PreparedStatement pstm = null;
		ResultSet rs = null;
		int count = 0;
		if(connection != null){
			StringBuffer sql = new StringBuffer();//sql语句
			sql.append("select count(1) as count from smbms_user u,smbms_role r where u.userRole = r.id");
			List<Object> list = new ArrayList<Object>();
			if(!StringUtils.isNullOrEmpty(userName)){//如果有参数 就经行判断 根据姓名来判断
				sql.append(" and u.userName like ?");
				list.add("%"+userName+"%");//0下标
			}
			if(userRole > 0){ //根据部门来 来联合查询
				sql.append(" and u.userRole = ?");
				list.add(userRole);
			}
			Object[] params = list.toArray();
			System.out.println("sql ----> " + sql.toString());
			rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
			if(rs.next()){
				count = rs.getInt("count");
			}
			BaseDao.closeResource(null, pstm, rs);
		}
		return count;
	}

3.useService

public int getUserCount(String queryUserName, int queryUserRole);

4.userServiceimpl

	@Override
	public int getUserCount(String queryUserName, int queryUserRole) {
		// TODO Auto-generated method stub
		Connection connection = null; //创建连接
		int count = 0;//定义返回的数据
		System.out.println("queryUserName ---- > " + queryUserName);
		System.out.println("queryUserRole ---- > " + queryUserRole);
		try {
			connection = BaseDao.getConnection();
			count = userDao.getUserCount(connection, queryUserName,queryUserRole);// 调用底层Dao 来查询返回数值
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			BaseDao.closeResource(connection, null, null);
		}
		return count;
	}

5.servlet

页面展示(和分页)
不管是什么操作都需要根据baseDao来写的
package cn.smbms.dao;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 操作数据库的基类--静态类
 * @author Administrator
 *
 */
public class BaseDao {
	
	static{//静态代码块,在类加载的时候执行
		init();
	}
	
	private static String driver;
	private static String url;
	private static String user;
	private static String password;
	
	//初始化连接参数,从配置文件里获得
	public static void init(){
		Properties params=new Properties();// 配置参数的对象
		String configFile = "database.properties";// 配置文件的位置
		InputStream is=BaseDao.class.getClassLoader().getResourceAsStream(configFile);
		try {
			params.load(is);
		} catch (IOException e) {
			e.printStackTrace();
		}
		driver=params.getProperty("driver");
		url=params.getProperty("url");
		user=params.getProperty("user");
		password=params.getProperty("password");

	}   
	
	
	/**
	 * 获取数据库连接
	 * @return
	 */
	public static Connection getConnection(){
		Connection connection = null;// 获取数据库链接
		try {
			Class.forName(driver);//通过反射的方式来 获取链接
			connection = DriverManager.getConnection(url, user, password);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return connection;
	}
	/**
	 * 查询操作
	 * @param connection
	 * @param pstm
	 * @param rs
	 * @param sql
	 * @param params
	 * @return
	 */
	public static ResultSet execute(Connection connection,PreparedStatement pstm,ResultSet rs,
			String sql,Object[] params) throws Exception{ //和下面的方法是差不多的就是多了返回值用的 set集合
		pstm = connection.prepareStatement(sql);
		for(int i = 0; i < params.length; i++){
			pstm.setObject(i+1, params[i]); //填补预编译时候的 参数
		}
		rs = pstm.executeQuery();// 执行sql语句
		return rs;
	}
	/**
	 * 更新操作
	 * @param connection
	 * @param pstm
	 * @param sql
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public static int execute(Connection connection //数据库链接
								,PreparedStatement pstm, // 预编译sql对象
								String sql,  //sql语句
								Object[] params// object 数组用来传递预编译的sql 用来拼接sql语句
								 ) throws Exception{//增删改操作 返回 的就是更新的行数
		int updateRows = 0;//返回受影响的行数
		pstm = connection.prepareStatement(sql);//获取
		for(int i = 0; i < params.length; i++){
			pstm.setObject(i+1, params[i]);//填补预编译时候的 参数
		}
		updateRows = pstm.executeUpdate();//执行sql语句 来返回行数
		return updateRows;
	}
	/**
	 * 释放资源
	 * @param connection
	 * @param pstm
	 * @param rs
	 * @return
	 */
	public static boolean closeResource(Connection connection,PreparedStatement pstm,ResultSet rs){ //关闭流资源
		boolean flag = true;
		if(rs != null){
			try {
				rs.close();
				rs = null;//GC回收
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				flag = false;
			}
		}
		if(pstm != null){
			try {
				pstm.close();
				pstm = null;//GC回收
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				flag = false;
			}
		}
		if(connection != null){
			try {
				connection.close();
				connection = null;//GC回收
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				flag = false;
			}
		}
		
		return flag;
	}

}

1.userdao

public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize)throws Exception;

currentPageNo 参数和 pageSize是用来分页的 参数
2.UserDaoIMpl

@Override
	public List<User> getUserList(Connection connection, String userName,int userRole,int currentPageNo, int pageSize)
			throws Exception {
		// TODO Auto-generated method stub
		PreparedStatement pstm = null; //获得数据库的操作对象
		ResultSet rs = null; 
		List<User> userList = new ArrayL ist<User>();//返回的List集合
		if(connection != null){
			StringBuffer sql = new StringBuffer(); //sql 语句拼接
			sql.append("select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.userRole = r.id");
			List<Object> list = new ArrayList<Object>(); //添加参数(预编译的sql 参数)的List 用来链接数据库语句
			if(!StringUtils.isNullOrEmpty(userName)){
				sql.append(" and u.userName like ?");
				list.add("%"+userName+"%");
			}
			if(userRole > 0){
				sql.append(" and u.userRole = ?");
				list.add(userRole);
			}
			sql.append(" order by creationDate DESC limit ?,?");
			currentPageNo = (currentPageNo-1)*pageSize;
			list.add(currentPageNo);
			list.add(pageSize);
			
			Object[] params = list.toArray();
			System.out.println("sql ----> " + sql.toString());
			rs = BaseDao.execute(connection, pstm, rs, sql.toString(), params);
			while(rs.next()){
				User _user = new User();
				_user.setId(rs.getInt("id"));
				_user.setUserCode(rs.getString("userCode"));
				_user.setUserName(rs.getString("userName"));
				_user.setGender(rs.getInt("gender"));
				_user.setBirthday(rs.getDate("birthday"));
				_user.setPhone(rs.getString("phone"));
				_user.setUserRole(rs.getInt("userRole"));
				_user.setUserRoleName(rs.getString("userRoleName"));
				userList.add(_user);
			}
			BaseDao.closeResource(null, pstm, rs);
		}
		return userList;
	}

3.service

	public int getUserCount(String queryUserName, int queryUserRole);

4.serviceImpl

@Override
	public int getUserCount(String queryUserName, int queryUserRole) {
		// TODO Auto-generated method stub
		Connection connection = null; //创建连接
		int count = 0;//定义返回的数据
		System.out.println("queryUserName ---- > " + queryUserName);
		System.out.println("queryUserRole ---- > " + queryUserRole);
		try {
			connection = BaseDao.getConnection();//调用 BaseDao 来链接数据库
			count = userDao.getUserCount(connection,queryUserName,queryUserRole);// 调用底层Dao 来查询返回数值
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			BaseDao.closeResource(connection, null, null);
		}
		return count;
	}

5 servlet 来和前端页面进行交互

获取角色的操作

为了统一 可以把每个表的角色操作都 另外创建一个包 和pojo 一一对应

用户显示Servlet

1.获取用户前端的数据 (查询)‘
2. 判断请求是否需要执行
3. 为了实现分页 需要计算当前页面和总页面 页面大小
4. 用户列表展示

private void query(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//查询用户列表
		String queryUserName = request.getParameter("queryname");
		String temp = request.getParameter("queryUserRole");
		String pageIndex = request.getParameter("pageIndex");// 从前端来获取数据

		int queryUserRole = 0;
		UserService userService = new UserServiceImpl();
		List<User> userList = null;
		//设置页面容量
    	int pageSize = Constants.pageSize;
    	//当前页码
    	int currentPageNo = 1;
		/**
		 * http://localhost:8090/SMBMS/userlist.do
		 * ----queryUserName --NULL
		 * http://localhost:8090/SMBMS/userlist.do?queryname=
		 * --queryUserName ---""
		 */
		System.out.println("queryUserName servlet--------"+queryUserName);  
		System.out.println("queryUserRole servlet--------"+queryUserRole);  
		System.out.println("query pageIndex--------- > " + pageIndex);
		if(queryUserName == null){
			queryUserName = "";
		}
		if(temp != null && !temp.equals("")){
			queryUserRole = Integer.parseInt(temp);
		}
		
    	if(pageIndex != null){
    		try{
    			currentPageNo = Integer.valueOf(pageIndex);
    		}catch(NumberFormatException e){
    			response.sendRedirect("error.jsp");
    		}
    	}	//判断参数是否需要查询!
    	//总数量(表)	
    	int totalCount	= userService.getUserCount(queryUserName,queryUserRole);//进行查询
    	//总页数
    	PageSupport pages=new PageSupport();
    	pages.setCurrentPageNo(currentPageNo);
    	pages.setPageSize(pageSize);
    	pages.setTotalCount(totalCount);//用阿里的代码进行实现分页
    	
    	int totalPageCount = pages.getTotalPageCount();
    	
    	//控制首页和尾页
    	if(currentPageNo < 1){
    		currentPageNo = 1;
    	}else if(currentPageNo > totalPageCount){
    		currentPageNo = totalPageCount;
    	}
		
		
		userList = userService.getUserList(queryUserName,queryUserRole,currentPageNo, pageSize);
		request.setAttribute("userList", userList);
		List<Role> roleList = null;
		RoleService roleService = new RoleServiceImpl();
		roleList = roleService.getRoleList();
		request.setAttribute("roleList", roleList);
		request.setAttribute("queryUserName", queryUserName);
		request.setAttribute("queryUserRole", queryUserRole);
		request.setAttribute("totalPageCount", totalPageCount);
		request.setAttribute("totalCount", totalCount);
		request.setAttribute("currentPageNo", currentPageNo); //用户 列表展示
		request.getRequestDispatcher("userlist.jsp").forward(request, response);// 返回前端页面
	}
增删改操作

一切的增删改操作都需要事务操作!

public class UserServiceImpl implements UserService{
	
	private UserDao userDao;
	public UserServiceImpl(){
		userDao = new UserDaoImpl();
	}
	@Override
	public boolean add(User user) {
		// TODO Auto-generated method stub
		
		boolean flag = false;
		Connection connection = null;
		try {
			connection = BaseDao.getConnection();
			connection.setAutoCommit(false);//开启JDBC事务管理
			int updateRows = userDao.add(connection,user);
			connection.commit();
			if(updateRows > 0){
				flag = true;
				System.out.println("add success!");
			}else{
				System.out.println("add failed!");
			}
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			try {
				System.out.println("rollback==================");
				connection.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}finally{
			//在service层进行connection连接的关闭
			BaseDao.closeResource(connection, null, null);
		}
		return flag;
	}

servlet 获取前端页面 封装 占90% 然后调用service 层

删除用户

也是用ajax方法来实现:

function deleteUser(obj){
	$.ajax({
		type:"GET", //什么方式提交
		url:path+"/jsp/user.do", // 转发到那个页面
		data:{method:"deluser",uid:obj.attr("userid")},//方法的名字用户的id 到userservlet中进行找匹配 然后执行方法
		dataType:"json",
		success:function(data){
			if(data.delResult == "true"){//删除成功:移除删除行
				cancleBtn();
				obj.parents("tr").remove();
			}else if(data.delResult == "false"){//删除失败
				//alert("对不起,删除用户【"+obj.attr("username")+"】失败");
				changeDLGContent("对不起,删除用户【"+obj.attr("username")+"】失败");
			}else if(data.delResult == "notexist"){
				//alert("对不起,用户【"+obj.attr("username")+"】不存在");
				changeDLGContent("对不起,用户【"+obj.attr("username")+"】不存在");
			}
		},
		error:function(data){
			//alert("对不起,删除失败");
			changeDLGContent("对不起,删除失败");
		}
	});
}

web 相关技术栈_第3张图片

文件上传

注意事项

1.为了保证服务器安全,上传文件应该放在外界无法直接访问的目录下 比如WEB-INF目录下
2.为了防止文件覆盖发生要上传文件的名字要唯一防止覆盖(txt 时间戳 uuid MD5 等)
3.要限制上传文件的最大值
4.可以上传文件的类型,在收到上传文件名的时候,判断后缀 是否一致

  • 需要用到的类
    ServletFileUpload 负责处理上传的文件数据,并且将表单中的,每个分装成一个Fileite对象,在使用ServletFileUpload对象解析请求时需要diskFileitemFactory对象,所以我们需要在进行解析过程之前构造好diskFileitemFactory对象,通过servletFileUpload对象的构造方法或者setFileitemFactory()方法来设置servletFileUpload对象的FileitemFactory的值;

Spring

1.1 简介

Spring : 春天 —>给软件行业带来了春天
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
很难想象Rod Johnson的学历 , 他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术

1.2 优点

Spring是一个开源免费的框架 , 容器 .
Spring是一个轻量级的框架 , 非侵入式的 .
控制反转 IoC , 面向切面 Aop
对事物的支持 , 对框架的支持
一句话概括:Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

1.3 组成

web 相关技术栈_第4张图片
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 .
web 相关技术栈_第5张图片
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory ,它是工厂模式的实现。 BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范
    与实际的应用程序代码分开。
  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
    Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中
  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口 MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText和 POI。
1.4 拓展
Spring Boot与Spring Cloud

Spring BootSpring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;
Spring Cloud基于Spring Boot实现的;
Spring Boot专注于快速方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 ,
Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使
用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。
SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。
web 相关技术栈_第6张图片

2、IoC基础
3.Spring 和Mybatis

先看先 Mybatis是如何操作的
1.实体类

import lombok.Data;

@Data
 public class User {
     private int id; //id

     private String name; //姓名

     private String pwd; //密码
 }
  1. UserMapper的接口
import java.util.List;

public interface UserMapper {
    List<User> selectUser();
}
  1. 写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="com.liubin.pojo.UserMapper"> //namespace 就是接口的实现类
    <select id="selectUser" resultType="com.liubin.pojo.User">
        select * from user
    </select>
</mapper>
  1. Mybatis的核心配置文件
 DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>    //别名
        <package name="com.kuang.pojo"/>
    typeAliases>
    <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/mybatis? useSSL=true&useUnicode=true&characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
    <mappers>   //mapper的映射
        <package name="com.kuang.dao"/>
    mappers>
configuration>

5.测试

import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class test {
    public static void main(String[] args) {
        SqlSession session = utils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> select = mapper.select();
        for (User user : select) {
            System.out.println(user);
        }
    }
}

6.总结:
注意 配置文件是用来链接数据库的 要在 链接的时候 (生成sqlSessionFactory的时候)然后用sqlSessionFactory来创建SqlSession
建立之后 ,sqlSession 然后获取Mapper 之后进行调用方法;

SqlSession能干什么?

SqlSession用途主要有两种

①. 获取对应的Mapper,让映射器通过命名空间和方法名称找到对应的SQL,发送给数据库执行后返回结果。

RoleMapper roleMapper = sqlSession.getMapper(RoleMapper.class);
Role role = roleMapper.getRole(1L);
②. 直接使用SqlSession,通过命名信息去执行SQL返回结果,该方式是IBatis版本留下的,SqlSession通过Update、Select、Insert、Delete等方法操作。

Role role = (Role)sqlSession.select(“com.mybatis.mapper.RoleMapper.getRole”,1L);
Mybatis底层利用JDK动态代理技术实现该接口,底层最后还是使用的IBatis中SqlSession通过Update、Select、Insert、Delete等方法操作。

整合实现一
Spring 和Mybatis整合之后的样子

所有的类都是由bean来管理 事务由aop来插入
把jdbc 链接封装成类
1.在spring-dao.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--配置数据源:数据源有非常多,可以使用第三方的,也可使使用Spring-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://localhost:3306/test? useSSL=true&useUnicode=true&characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="19182030"/>
    </bean>
    <!--配置SqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/> <!--关联Mybatis-->
        <property name="configLocation" value="classpath:application.xml"/>
        <property name="mapperLocations" value="classpath:com/liubin/pojo/*.xml"/>
    </bean>
    <!--注册sqlSessionTemplate , 关联sqlSessionFactory-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <!--利用构造器注入-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>
    <bean id="userMapper" class="com.liubin.pojo.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>
</beans>

在这个注册文件中,可以发现 我们注册了dataSource 类和sqlSessionFactory 和 sqlSession 类之后还注册了userMapper 类用来生成sqlSession,
2.查看之前的application.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>
    <typeAliases>
        <package name="com.liubin.pojo"/>
    </typeAliases>
</configuration>

就会发发现spring的配置文件已经把mybatis的配置文件整合了,
3.UserMapperImpl的类实现

import org.mybatis.spring.SqlSessionTemplate;

import java.util.List;

public class UserMapperImpl  implements UserMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

4.测试类

import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class test {
   public static void main(String[] args) {
      ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-dao.xml");
      UserMapper userMapper = applicationContext.getBean("userMapper", UserMapper.class);
      List<User> users = userMapper.selectUser();
      for (User user : users) {
         System.out.println(user);
      }
   }
}

永远就是用户调用bean来进行操作方法:

整合实现二

mybatis-spring1.2.3版以上的才有这个 .
官方文档截图 :
dao继承Support类 , 直接利用 getSqlSession() 获得 , 然后直接注入SqlSessionFactory . 比起方式1 , 不
需要管理SqlSessionTemplate , 而且对事务的支持更加友好 . 可跟踪源码查看
web 相关技术栈_第7张图片

测试:

  1. 将我们上面写的UserDaoImpl修改一下
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    @Override
    public List<User> selectUser() {
        SqlSession sqlSession = getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }

}

和之前的进行对比发现

public class UserMapperImpl  implements UserMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

这里的SqlSessionTemplate 是外面传进来的 但是继承了SqlSessionDaoSupport 之后就不需要在从外面传入SqlSessionTemplate 了
直接getSqlSession 就可以得到SqlSession
也是需要传入参数的 因为虽然SqlSessionDaoSupport 没有参数 但是他的父类需要 在Spring文件中进行注册

    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> 
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    bean>
 <bean id="userMapper" class="com.liubin.pojo.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    bean>  //之前的
    <bean id="UserMapper2" class="com.liubin.pojo.UserMapperImpl2">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    bean>//之后的 需要传入sqlSessionFactory 
声明式事务

事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!
事务管理是企业级应用程序开发中必备技术,用来确保数据的完整性和一致性。
事务就是把一系列的动作当成一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
事务四个属性ACID

  1. 原子性(atomicity)
    事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起
    作用
  2. 一致性(consistency)
    一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中
  3. 隔离性(isolation)
    可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损
  4. 持久性(durability)
    事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中
Spring中的事务管理

Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以
使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。

  • 编程式事务管理
    将事务管理代码嵌到业务方法中来控制事务的提交和回滚
    缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
  • 声明式事务管理(AOP)
    一般情况下比编程式事务好用
    将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
    将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务
    管理。

SpringMVC

1.1、什么是MVC

MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。
MVC主要作用是降低了视图与业务逻辑间的双向偶合。
MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异

你可能感兴趣的:(笔记,java,tomcat,spring,maven)