Junit单元测试
- 感谢陈长宏老师
测试的分类:
- 黑盒测试
- 白盒测试
定义一个测试类
- 测试类名 被测试的类名 + Test
- 包名:xxx.xx.xx.test cn.itcast.test
定义一个测试方法:可以独立运行
- 方法名:test测试的方法名 testAdd
- 返回值 :void
- 参数列表 :空参数
给方法加一个注解 @Test
添加Junit依赖
判定一个结果,红色代表失败,绿色成功
@Before
@After
package cn.itcast.test;
import cn.itcast.junit.Calcuator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CalcuatorTest {
@Before
//用于资源申请,所有测试方法执行前都会先执行该方法
public void init()
{
System.out.println("init...");
}
@After
//释放资源,所有测试方法执行完成之后,都会执行该方法
public void close()
{
System.out.println("closing");
}
@Test
public void testAdd()
{
Calcuator calcuator = new Calcuator();
// int i = 3 / 0;
int res = calcuator.add(1,1);
//断言Assert
Assert.assertEquals(2,res);
}
}
反射:框架设计的灵魂
框架:半成品软件,在框架基础上进行开发,简化编码
反射:将类的各个组成部分封装为其他对象,就是反射机制。
反射的好处
- 可以在程序运行过程中,操纵这些对象
- 可以解耦,提高程序的可扩展性
获取class对象的方式
- 1.class.forName("全类名"):将字节码文件加载进内存,返回class对象(多用于配置文件,将类名定义在配置文件中。读取文件,加载类)
- 2.类名.class:通过类名的属性class获取(多用于函数中参数的传递)
- 3.对象.getclass():getclass()方法Object中定义(多用于对象的获取字节码的方式)
- 结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取的Class对象都是同一个
class对象的功能:
- 获取的功能
- 获取成员变量们
- Field[] getFields() 获取所有public修饰的成员变量
- Field getField(string name) 获取指定名称的public成员变量
- Field[] getDeclaredFields() 获取所有修饰的成员变量Field 包括private
- Field getDeclaredField(string name) 获取指定修饰的成员变量Field 包括private
- 获取构造方法们
- constructor<?>[] getconstructors()
- constructor
getconstructor(类<?>... parameterTypes) - constructor
getDeclaredconstructor(类<?>... parameterTypes) - Constructor<?>[] getDeclaredconstructors()
- 获取成员方法们
- Method[] getMethods()
- Method getMethod(string name,类<?>... parameterTypes)
- Method[ ] getDeclaredMethods()
- Method getDeclaredMethod(string name,类<?>... parameterTypes)
- 获取类名
- String getName()
- 获取成员变量们
Field:成员变量(操作)
- 设置值 set()
- 获取值 get()
// a 是 xxx类中的一个public属性
Filed a = xxxclass.getField("a");
// 获取成员变量a的值
xxx p = new xxx();
Object value = a.get(p);
// 设置a的值
a.set(p,"张三");
// d是xxx类的一个私有属性
// 获取名字为d的成员变量
Field d = xxxClass.getDeclareField("d");
d.setAccessible(true); // 忽略访问权限修饰符的安全检查(暴力反射)
Object value = d.get(p);
System.out.println(value);
Constructor:获取构造方法(区分构造方法,参数不同。获取的构造方法名字必须和类名相同)
- 创建对象
- T newInstance()
Constructor constructor = xxxClass.getConstructor(String.class, int.class)
//创建对象
Object x1 = constructor.newInstance("张三",23)
//空参构造
Object o = xxxClass.newInstance();
获取各成员方法们
Methon :方法对象
-
invoke(参数列表)
Method method1 = xxxClass.GetMethod("方法名",int.class,int.class); xxx x1 = new xxx(); method1.invoke(x1, 1 , 1); //获取所有public修饰方法 Method[] methods = xxxClass.getMethods(); for(Method method : methods) { sout(method); //暴力反射 method.setAccessible(true); //获取方法名称 String name = method.getName(); } //获取类名的操作 Strin className = xxxClass.getClassName();
注解
-
概念:
-
注释:用文字其描述程序的,给程序员看的
-
注解:说明程序的,给计算机看的
- JDK1.5之后的新特性
- 说明程序的
作用
- 编译检查,@注解名称
- 编写文档,javadoc 命令生成api文档
- 代码分析,通过代码里标识的注解进行分析。【使用反射】
-
JDK 预定义注解:@Override,@Test...
-
自定义注解
-
格式
-
注解 public @interf ace 注解名称
-
javap 反编译
-
注解上本质上就是接口 public interface 注解名称 extends java.lang.annotation.Annotation{}
-
属性:接口中可以定义的成员变量(常量,接口抽象方法 public abstract 可以省略)
-
要求
- 1.属性的返回值类型
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型数组
- 1.属性的返回值类型
-
定义了注解的属性,在使用时需要给属性赋值
-
如果定义属性值,使用default关键字给属性默认初始化值,则在使用注解时,不用给值。
-
如果只有一个属性需要赋值,并且属性名称是value,则可以直接定义值
-
数组赋值时,值使用{}
-
-
-
-
元注解,描述注解的注解
- @Target:描述注解能够作用的位置
- ElementType取值(@Target的取值):
- TYPE:作用类上(ElementType.Type)
- METHOD:作用于方法上
- FIELD:作用于成员变量上
- ElementType取值(@Target的取值):
- @Retention:描述注解被保留的阶段
- @Retention(RententionPolicy.RUNTIME):当前被描述的注解,会被保留到class字节码文件中,并被JVM读取到
- @Documented:描述注解是否被抽取到API文档中去
- @Inherited:描述注解是否被子类继承
- @Target:描述注解能够作用的位置
-
-
程序中(解析)使用注解(获取注解中定义属性值)
- 获取注释定义位置的对象(class, method, field)
- 获取指定的注解
- getAnnotation(class)
- 调用注解中的抽象方法获取配置的属性值
小结:
- 以后大多是时候,只会使用注解,而不知定义注解
- 注解是给谁用?
- 编译器
- 给解析程序用(测试程序)
- 注解不是程序的一部分,可以理解为注解就是一个标签。
DCL管理用户
sql的分类
- DDL :操作数据库和表
- DML:增删改表中的数据
- DCL:查询表中的数据
- DQL:管理用户和授权
DBA 数据管理员 专门管理数据库,会给公司得员工分权限。
1.管理用户
- 添加用户
- create user '用户名' @ '主机名' identified by '密码'
- 当主机名为 % 时表示可以再任何主机访问
- 删除用户
- drop user '主机' @ '主机名'
- 修改用户密码
- update user set password = password('新密码') where user = ' 用户名 '//password()为加密函数
- set password for '用户名' @ '主机名' = password('新密码')// 不同语法
- 忘记root密码怎么办
- cmd - > net stop mysql//需要管理员运行//
- 启动mysql服务,使用不验证mysqld -- skip - grant - tables
- 打开新的cmd窗口,输入mysql 回车成功
- use mysql update user set password = password('新密码')where user = ' root'
- 关闭两个窗口
- 打开任务管理器,手动结束mysqld.exe进程
-
查询用户
2.授权
- 查询权限
- show grant for '用户名' @ '主机名'
- 授予权限
- grant 权限列表 on 数据库.表名 to '用户名' @ '主机名'
- grant all on
*.*to '用户名' @ '%' // 授予对全部库的全部权限
- 撤销权限
- revoke 权限列表 on 数据库表.表明 from '用户名' @ ' 主机名'
JDBC
概念 : java dataBase Connectivity
JDBC本质:定义了操作所有关系型数据库的接口 ,各个数据库厂商去实现这套接口,提供数据库驱动jar包,我们可以使用这套接口编程,真正执行的代码,是驱动jar包的实现类
快速入门
-
步骤
-
导入驱动jar包
- 复制到libs文件夹中
- 右键 libs add as library
-
注册驱动
-
获取数据库连接对象 Connection
-
定义sql语句
-
获取执行sql语句的对象 statement
-
执行sql 接受返回结果
-
处理结果
-
释放资源
-
各个对象
-
Java MySQL 连接 | 菜鸟教程 (runoob.com)mysql 8.0以上会有区别这个网址上提出了8.0以上的代码
-
DriverManager 驱动管理对象
-
注册驱动:告诉程序是用哪个数据库驱动
-
static void registerDirver( Driver driver):注册于给定程序的驱动 DriverManager. 写代码时使用:Class.forName("com.mysql.jdbc.Driver") 通过查询源码发现:在com.mysql.jdbc.Driver类中存在静态代码块 static{ try{ java.sql.DriverManageer.registerDriver(new Driver()) } catch(SQLException E){ throw new RuntimeException("can't register driver!") } } -
获取数据库连接
-
static Connection getConnection(String url ,String user,String password) url:指定连接路径("jdbc:mysql://ip:端口/databaseName")
-
-
-
Connection 数据库连接对象
- 获取执行sql的执行对象 createStatement()
- 也是执行sql的对象prepareStatement(String sql)
- 管理实务:
- 开启事务 setAutoCommit()调佣该方法设置参数为false,季开启事务
- 提交事务 commit()
- 回滚事务 rollback()回滚事务
-
ResultSet 结果集对象,封装查询结果(二维表)
- boolean next() //游标向下移动一行
- getXxx(参数):获取数据 Xxx代表数据类型 如getString(),getInt();
- 参数 int 代表列的编号从1开始
- 参数 字符串,代表列名
-
Statement 执行 静态 sql对象
- 执行sql
- exceute(sql) :可以执行任意sql 不用
- executeUpatde(sql):执行DML语句(insert,delete,update)返回值是影响的行数,可以通过映像函数,判断,sql语句是否执行成功,如果返回值>0则成功,反之失败
- executeQuerry(sql) 执行DQL select,返回 ResultSetx
- p91
- 执行sql
-
PreparedStatement 执行sql对象
- sql注入问题:在拼接sql时,有一些sql特殊关键字参与字符串的拼接,造成安全问题
- 输入用户随便,输入密码为 a' or 'a' = 'a 永真式
- 解决sql注入问题:使用prepareStatement对象来解决
- 预编译的sql:参数使用 ?作为占位符,执行sql给?赋值
- 使用步骤
- 导入jar包
- 注册驱动
- 获取数据库连接对象
- 定义sql 参数使用?作为占位符
- 获取Connection.preparedStatement(String sql)
- 给?赋值
- 使用setXxx(参数1(问号位置),参数2(问号对应的值))
- 执行sql
- 释放资源
- 后期都会使用PreparedStatement
- 防止sql注入
- 效率更高
List 和 ArrayList的区别
- sql注入问题:在拼接sql时,有一些sql特殊关键字参与字符串的拼接,造成安全问题
-
List 和 ArrayList的区别
抽取JDBC 工具类: JDBCUtils
- 简化书写
- 抽取一个方法注册驱动
- 抽取一个方法释放资源
- 抽取一个方法获取连接
- 不想传递参数,还需保证工具类的通用性
- 解决方案:配置文件
- jdbc.properties
- url = ,user = , password =
- jdbc.properties
- 使用Properties类读取资源文件
JDBC控制事务
- 事务:一个包含多个步骤的业务操作,如果这业务被事务管理,则躲个步骤同时成功,或者同时失败
- 操作
- 开启事务
- 提交事务
- 回滚事 务
- 使用Connection对象来管理事务
- setAutoComit():参数为False即开启事务
- 在执行sql之前开启事务
- commit()提交事务
- 当所有sql都执行完提交事务
- rollback()回滚事务
- 在catch中回滚事务
- setAutoComit():参数为False即开启事务
JDBC代码
JDBC工具类
package cn.itcast.util;
public class JDBCUtils {
//静态变量才能被静态代码块和静态方法访问
private static String url;
private static String user;
private static String password;
private static String driver;
static{
try {
// 创建Properties集合类
Properties pro = new Properties();
// 获取src路径下文件,使用ClassLoader类加载器
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
// URL定位了文件的绝对路径
URL res = classLoader.getResource("jdbc.properties");
// 获取字符串路径
String path = res.getPath();
// 读取文件
pro.load(new FileReader(path));
// 给静态变量赋值
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
driver = pro.getProperty("driver");
// 注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection GetConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
}
//释放资源
public static void close(Statement stmt, Connection conn)
{
if(stmt != null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
// 重载释放资源的函数
public static void close(ResultSet rs, Statement stmt, Connection conn)
{
if(rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
JDBC配置文件 -- jdbc.properties
url = jdbc:mysql://localhost:3306/jdbclearn?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
user = root
password = 123456
driver = com.mysql.cj.jdbc.Driver
JDBC测试类(转账的事务)
package cn.itcast.jdbc;
public class JDBCdemo01 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
//获取连接
connection = JDBCUtils.GetConnection();
//开启事务
connection.setAutoCommit(false);
String sql1 = " update account set balance = balance - ? where id = ?";
String sql2 = " update account set balance = balance + ? where id = ?";
pstmt1 = connection.prepareStatement(sql1);
pstmt2 = connection.prepareStatement(sql2);
pstmt1.setInt(1,500);
pstmt1.setInt(2,1);
pstmt2.setInt(1,500);
pstmt2.setInt(2,2);
pstmt1.executeUpdate();
pstmt2.executeUpdate();
//提交事务
connection.commit();
} catch (Exception throwables) {
//事务回滚
try {
if(connection != null)
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}finally{
JDBCUtils.close(pstmt1,connection);
JDBCUtils.close(pstmt2,null);
}
}
}
2021/7/13
数据库连接池
概念:是一个容器,存放数据库连接的容器,当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户访问数据库时,从容其中获取连接对象,用户访问完成之后,会将连接对象归还给容器
-
优点
- 节约资源
- 访问高效
-
实现:
- 标准接口:DataSource
- 获取连接 getConnection
- 归还连接:如果归还对象 Connection是从连接池获取的,那么调用Connection.close()方法,则不会再关闭连接了,而是归还连接。
- 一般我们不去实现他,有数据库厂商去实现
- 标准接口:DataSource
-
C3P0:数据库连接池技术
- 步骤、
- 导入jar包 c3p0,有依赖的jar包和数据库mysql的驱动jar包
- 定义配置文件名称为c3p0.properites 或者 c3p0-config.xml 路径在项目的类路径下面(src目录下)
- 创建核心对象,数据库连接池对象 ComboPooledDataSource
- 获取连接 :getConnection
- 步骤、
-
Druid:数据库连接池技术,由阿里提供
-
导入jar包,和 数据库连接包
-
加载配置文件
Properties pro = new Properties();InputStream is = 当前类名.class.getClassLoader().getResourceAsStream("durid.properties")pro.load(is); -
定配置文件
- 是properties形式的
- 可以叫任意名字,任意位置
- 获取数据库连接池对象,通过工厂类来获取DataSource ds = DuridDataSourceFactory.createDataSource(Properties pro)
- 获取连接 getConnection
-
-
durid工具类
-
定义一个类JDBCUtils
-
提供静态代码块加载配置文件,初始化连接池对象
-
提供方法
-
获取连接方法:通过数据库连接池获取连接
-
释放资源
-
获取连接池的方法
-
一直出现错误 Access denied for user 'root '@'localhost' (using password: YES) 到最后才发现配置文件的user=root,而正确的是username=root
-
-
Durid代码
Durid工具类
package cn.itcast.util;
public class JDBCUtils01 {
private static DataSource ds;
//把DataSource
static{
// 加载配置文件
Properties pro = new Properties();
try {
pro.load(JDBCUtils01.class.getClassLoader().getResourceAsStream("durid.properties"));
//获取datasource
ds = DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
//释放资源
public static void close(Statement stmt, Connection conn)
{
if(stmt != null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close(); //归还给对象
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(ResultSet rs, Statement stmt, Connection conn)
{
if(rs != null){
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close(); //归还给对象
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
//获取连接池的方法
public static DataSource getDataSource()
{
return ds;
}
}
Durid测试类
package cn.itcast.jdbc;
public class DuridDemo01 {
static PreparedStatement pstmt = null;
static Connection conn = null;
public static void main(String[] args) {
try {
//获取连接
conn = JDBCUtils01.getConnection();
//定义sql语句
String sql = "insert into account values(?,?,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1,5);
pstmt.setString(2,"zyc1");
pstmt.setString(3,"zyc1");
pstmt.setInt(4,3000);
pstmt.executeUpdate();
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally{
JDBCUtils01.close(pstmt,conn);
}
}
}
包的名称
com.alibaba:druid:1.1.10
durid.properites //Durid的配置文件
- 注意键名
- 还有就是末尾空格和开头空格一定要看好,mysql会把末尾的空格也算到输入里去
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbclearn?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
minIdle=3
Spring JDBC : JDBC Template
-
Spring框架对JDBC的简单封装,提供了JDBC Template对象来简化JDBC的开发
-
步骤
-
导入JAR包 很多个jar包 数据库连接池 数据库驱动包 和 Template的多个包
-
创建JDBC Template对象 ,依赖于数据源DataSource
JdbcTemplate jt = new JdbcTemplate(DataSource ds)
-
调用JdbcTemplate方法来完成CRUD(增删改查)
-
update():执行DML:增删改
-
queryForMap():查询结果封装为map集合,结果长度只能是1,列名为键,值为values
-
queryForList():查询结果封装为list集合
-
query():查询结果封装为JavaBean集合
-
List<Emp> list = JdbcTemplate.query(sql, new BeanProPertyRowMapper<Emp>(Emp.class)); 其中Emp是JavaBean类,query是JdbcTemplate对象的一个方法。Emp是自定义的? 注:把JavaBean类中的所有基本类型的属性类似int,double都变成Integer和Double使他们可以接受null值,因为在数据库存储过程中,可能会有null的赋值 -
queryForObject():查询结果封装为对象,用于聚合函数的查询
-
-
使用JdbcTemplate进行数据库操作的代码
public class JdbcTemplate01 {
public static void main(String[] args) {
// 新建一个JdbcTemplate对象
JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils01.getDataSource());
//调用方法
String sql = "update account set balance = 2400 where id = ?";
//第一个参数是sql语句,第二个是问号内的值,问号顺序依此从左到右排开
int col = jdbcTemplate.update(sql,1);
System.out.println(col);
}
}
从直接调用 - > JDBC工具类 - > 数据池工具类 - >JdbcTemplate 只能说越来越方便,但同时学习的过程也是递进的,将来也是不能只会调用,不要求能直接写出来什么什么工具类,但能说出步骤。
web概念概述
-
javaweb:
- 使用java语言开发基于互联网项目
-
软件架构
- B/S:Browser/Server
- 开发 安装 部署 维护简单
- 应用过大,用户体验可能不好,模型加载的慢
- C/S:Client/Server
- 开发 安装 部署 维护 麻烦
- 用户体验好
- B/S:Browser/Server
-
B/S
- 资源分类
- 静态资源
- 使用静态网页开发技术发布的资源
- 特点:
- 所有用户访问,得到的结果都是一样的(HTML,CSS,JavaScript)
- 如果用户请求是静态资源,那么服务器会直接将静态资源发送给浏览器,浏览器中内置了静态资源的解析引擎,可以展示静态资源
- 动态资源
- 使用动态网页及时发布的资源
- 特点
- 所有用户访问,得到的结果可能不一样
- 如 jsp/servlet..
- 如果用户请求的是动态资源,那么服务器会执行动态资源,转换为静态资源,在发送给浏览器
- 静态资源
- 资源分类
-
静态资源
- HTML: 用于搭建基础网页,展示页面内容
- CSS :用于美化页面,布局页面
- JavaScript:控制页面的元素,让页面有一些动态效果(动态效果!=动态资源)
CSS
页面美化,布局控制
概念:Cascading Style Sheets 层叠样式表
- 层叠:多个样式可以作用在同一个html元素上,同时生效
优点:
- 功能强大
- 将内容展示和样式控制分离
- 降低耦合度,解耦
- 让分工协作更容易
CSS的使用:css与html结合方式
-
内联样式
-
在标签内使用style属性指定css代码
<div style="color:red;">hello </div>
-
-
内部样式
- 在head标签内,定义Style标签,style标签的标签内容就是css代码
-
外部样式
-
定义css资源文件
-
在head标签内,定义link标签,引入外部资源文件
-
<link rel="stylesheet" href="css/xxx.css">或者<style>@import "css/xxx.css"</style>
-
-
注意三种css的范围
-
2,3方法常用
CSS的语法
-
格式
选择器{
属性名1:属性值1;
属性名2:属性值2;
}
-
选择器:筛选具有相似特征的元素
-
注意:
- 每一对属性键值对需要使用分号隔开
选择器:筛选具有相似特征的元素
-
分类
-
基础选择器
-
id选择器:选择具体id属性值的元素
- 语法
<style>#id { color:red}</style> -
元素选择器:选择具有相同标签名称的元素
- 语法
<style>标签名称 { color:red}</style> -
类选择器:选择具有相同的class属性值得元素
- 语法
<style>.类名 { color:red}</style>
-
-
扩展选择器
-
选择所有元素
*{} -
并集选择器
选择器1,选择器2{} -
子选择器:筛选选择器1元素下的选择器2元素
选择器1 选择器2 {}div p {}表示div下的p生效 -
父选择器:筛选选择器2的父元素选择器1
选择器1 > 选择器2 {}div > p {} 对p所在的div进行 -
属性选择器:选择元素名称,属性名=属性值的
元素名称[属性名="属性值"]{}input[type='text']{ }-
伪类选择器
元素:状态{}a:link{}a:hover{}a:active{}a:visited{}
-
-
属性:
- 字体
- 文本
- 背景
- 边框
- 尺寸
- 盒子模型:控制布局
- margin:外边距
- padding:内边距
- 内边距会影响盒子大小
- box-sizing:border-box;设置盒子属性,让width和height就是最终盒子大小
- float:浮动
- left
- right
JavaScript
概念:一门客户端脚本语言
- 运行在客户端浏览器中,每一个浏览器都有JavaScript的解析引擎
- 脚本语言:不需要编译,直接就可以被浏览器解析执行了
功能:可以来增强用户和html的交互过程,可以来控制html元素,实现让页面有动态效果,增强用户体验
JavaScript发展史:略,总结来说JavaScript和Java的关系,就是雷锋和雷峰塔的关系(名字类似,但各个语言其实本质都类似)
JavaScript = ECMAScript +BOM(对象)+ DOM(对象)
ECMAScript ,所有客户端脚本语言的标准
ECMAScript
-
基本语法
-
与html结合方式
- 内部JS
<script> alert("nihao");</script>- 外部JS
<script src="a.js"></script> -
注释
- 单行//
- 多行 /* */
-
数据类型
- 原始数据类型(基本数据类型)
- number:整数、小数、NaN(not a number)
- string:字符串
- boolean:true、false
- null:一个对象为空的占位符
- undefined:未定义,如果一个变量没有给初始化值,则会被默认赋值为undefined
- 引用数据类型(对象)
- 原始数据类型(基本数据类型)
-
变量:一小块存储数据的内存空间(var)
-
Java是强类型语言,而JavaScript是弱类型语言
-
强类型语言 int a = 3,在开辟变量存储空间时,定义了空间将来存储的数据类型,只能存储固定类型的数据
-
弱类型语言 var a = 3,在开辟变量存储空间时,不定义空间将来存储数据类型,可以存放任意类型的数据
-
var 变量名 = 初始化的值;
输出换行document.write(x + "<br>");
-
-
运算符
输出var类型typeof(变量名)-
一元运算符
- ++,--
- +,- 正负号,在JS中如果运算数不是运算符所要求的类型,那么JS会自动将运算数进行类型转换
- string转number
+"123",如果字面值不是数字,则转换为NaN =+"abc" - Boolean转number true = 1,false = 0
-
算术运算符
- 3 / 4 = 0.75(与java不同弱类型语言,不会自动取整)
-
赋值运算符
- =,+=...
-
比较运算符
- === 全等于,在比较之前,先判断类型,如果类型不一样则直接返回false
- == 等于
- 类型不同,先进性类型转换,再比较
-
逻辑运算符
-
&&
-
||
-
!
-
其他类型转Boolean
-
number转
- 0和NaN假,非0为真
-
string转 :除了空字符串都是true
-
null,undefined都是false
-
对象,所有对象都是true
js 中if(obj)//防止空指针,因为所有对象都是true{ ...}java中if(obj != null && obj.length > 0){ ...} -
-
-
三元运算符
-
?:表达式
-
a > b ? 1 : 0
-
-
-
流程控制语句
- switch,在java中可以接受的数据类型,byte,int,shot,char,枚举,字符串
- 在js中,switch,可以接受任意基础数据类型
-
特殊语法
- 可以省略分号,但不建议
- 可以省略
var- 使用var,是局部变量
- 不适用var,是全局变量
-
html中的空格,
 
-
-
基本对象
- Function:函数(方法)对象
1.创建方法对象 1.var fun = new Function(形式参数名字列表,方法体);忘了吧 2.function 方法名称(形式参数列表){//最常用的 方法体 } 3.var 方法名 = function(形式参数列表) { 方法体 }2.方法3.属性 length:表示形参的个数4.特点 方法形参类型可以省略,返回值类型也可以省略 方法是一个对象,如果定义一个相同的方法,会覆盖和不是重载。 在调用方法时,可以给js方法传入0个参数,或任意个参数,都是不报错的。 在方法声明中有一个隐藏的内置对象(数组),arguments,封装了所有的实际参数。 function add() { var sum = 0; for(var i = 0; i < arguments.length; i++) { sum += arguments[i]; } return sum }5.调用方法名称(实际参数列表)- Array
- Boolean
- Date
1.创建方法对象 1.var date = new Date();2.方法 1.toLocaleString():返回当前Date对象对应的时间的本地字符串格式 2.getTime();时间戳,返回当前时间-1970/1/1的毫秒差- Math
1.创建方法对象 不需要创建,直接使用Math.方法名字2.方法 random():返回0-1之间的随机数[0,1) cell():上取整 floor():下去整 round():四舍五入 var number = Math.floor((Math.random() * 100)) + 1; [1,100]随机数-
Number
-
String
-
RegExp
- 1.正则表达式:定义字符串的组成规则
- 单个字符 : []
- [a]
- [ab] ,a或者b
- [a-zA-Z0-9_] 小写或者大写字母和下划线
- \d:单个数字字符[0-9]
- \w:单个单词字符[a-zA-Z0-9_]
- 量词符号:
*:出现0或多次?:出现0或1次+:出现1次或多次- {m,n}:表述数量在[m,n]之间,m如果缺省,{,n}表述最多n次,如果n缺省{m,}表示最少多少次
- 开始结束符号
- ^:开始
- $:结束
- 单个字符 : []
- 正则对象
1.创建方法对象 1.var reg = new RegExp("正则表达式"); 2.var reg = /正则表达式/ //无双引号2.方法 1.test(参数);验证指定参数字符串是否符合该正则表达式 var reg = /^\w{3,4}$/; var reg = new RegExp("^\\w{3,4}$");取消\的转义功能 alert(reg.test("asf")); - 1.正则表达式:定义字符串的组成规则
-
Global
- 全局对象,封装的方法不需要对象直接调用,也不是静态方法,直接 -- 方法名()
- 方法
encodeURI(); url编码 decodeURI(); url解码 encodeURIComponent(); url编码,相比上面编码的字符更多 decodeURIComponent(); url解码,相比上面编码的字符更多 parseInt():将字符串转换为数字,也可以直接使用+强制转换 逐一判断每个字符是否是数字,直到不是数字为止,将前面转换为number NaN == NaN 结果永远都是返回false,所以可以使用isNaN()判断是否是NaN eval();计算字符串,将此字符串转换为脚本代码执行,用于AJAX的交互
DOM(对象)
-
功能:控制html文档的内容
-
代码:获取当前页面标签(元素),对象Element
- document.getElementById("id值"):通过元素id获取元素对象
-
操作Element对象:
- 修改属性值
- 明确获取的对象是哪一个
- 查看API文档,找其中有哪些属性可以设置
- 修改标签体内容
- 属性:innerHTML
- 修改属性值
-
事件的简单学习
- 功能:某些组件被执行了某些操作后,触发某些代码的执行
- 如何绑定html事件
- 直接在html标签上,指定事件的属性(操作),属性值就是js代码 --onclick 单击事件
- 通过js获取元素对象,指定事件属性,设置一个函数
var light = document.getElementById("light"); var flag = false; //绑定单机时间 light.onclick = function (){ if(flag) { light.src = "off.gif"; flag = false; } else { light.src = "on.gif"; flag = true; } }
BOM (对象)
概念:Browser Object Model 浏览器对象模型
- 将浏览器封装为对象
- Window:窗口对象
1.创建方法对象
2.方法
1.与弹出框有关的方法
window.alert(); == alert();,弹出警告框
confirm():显示一段消息,有确认按钮和取消按钮
点击确定按钮,返回true
点击取消按钮,返回false
prompt():显示可提示用户输入的对话框
返回值是输入框的值
2.与打开关闭有关的方法
open():打开新窗口,返回一个新的window对象
close():关闭当前窗口
3.定时器有关的方法
setTimeout(); 在指定的毫秒数后调用函数或者计算表达式
参数1 js代码或者方法函数对象,"fun()",或者直接写fun,fun为函数名称 参数2 毫秒值
返回值,id,供取消函数参数使用
clearTimeout; 取消由setTimeout()方法设置的Timeout
setInterval(); 按照指定周期来调用函数或者计算表达式
参数1 js代码或者方法函数对象,"fun()",或者直接写fun,fun为函数名称 参数2 毫秒值
返回值,id,供取消函数参数使用
clearInterval(); 取消setInterval()设置timeout
3.属性
1.获取其他BOM对象:
history 定义 var history1 = window.history; window可以省略
location
Navigator
Screen
2.获取DOM对象
document 定义 var document1 = window.document; 也可以window直接省略
4.特点
Window对象可以不需要创建可以直接使用,window.方法名();
或者也可以直接不写 window,直接写 方法名();
轮播图案例
<img id ="img01" src="img/BigSur01.jpg" width="100%" height="50%" alt="">
<script>
var num = 1;
function fun(){
if(num > 2) num = 1;
var element = document.getElementById("img01");
element.src="img/BigSur0"+num+".jpg";
num++;
}
//定义定时器
setInterval(fun,3000);
</script>
-
Navigator:浏览器对象
-
Screen:显示器屏幕对象
-
history:历史记录对象
- 当前窗口的历史记录
1.创建 var history = window.history; var history = history; 2.方法 1.back(); 加载 history 列表中的前一个url 2.forward(); 加载 history 列表中的后一个url 3.go(); 加载 history 列表中的某个具体页面 参数 正数,前进几个history 负数,倒退几个history 3.属性 length:返回当前窗口历史列表中的URL数量 <input id="btn" type="button" value="xxx"><script> var id = document.getElementById("btn"); id.onclick=function () { document.write(history.length); }</script> -
location:地址栏对象
1.创建方法对象 1.window.Location; 2.Location;2.方法 1.reload();重新加载文档,刷新3.属性 1.href:设置或者返回当前浏览器的URL路径 <body> <input id="button1" type="button" value="刷新" align="center"> <input id="button2" type="button" value="百度" align="center"> <script> //1.获取按钮对象 var id = document.getElementById("button1"); //2.绑定单击事件 id.onclick = function () { //刷新 location.reload(); } //获取当前的URL document.write(location.href); //设置url为百度 var id1 = document.getElementById("button2"); id1.onclick=function(){ //跳转到百度 location.href="https://www.baidu.com"; } </script></body>
倒计时跳转案例
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
P{
text-align:center;
}
span{
color: goldenrod;
}
</style>
</head>
<body>
<p>
<span id="time">5</span>秒之后,自动跳转到百度
</p>
<script>
/*
1.显示页面效果 p标签
2.秒数的倒计时读秒
2.1 定义一个方法,获取span标签,修改span的内容使其减一
2.2 定义一个定时器,1s执行一次
*/
var second = 5;
var id = document.getElementById("time");
function fun(){
second--;
if(second==0)
{
location.href="https://www.baidu.com";
}
id.innerHTML=second;
}
setInterval(fun,1000);
</script>
</body>
DOM(对象)
-
Document Object Model 文档对象模型
- 将标记语言文档的各个组成部分 ,封装为对象。可以使用这些对象,对标记语言进行CRUD的动态操作
-
W3C DOM标准被分成3个部分
- 核心DOM - 针对任何结构化文档的标准模型
- Document :文档对象
- Element:元素对象
- Attribute:属性对象
- Text:文本对象
- Comment:注释对象
- Node:节点对象,针对上面5个的父对象
- XML DOM - 针对XML文档的标准模型
- HTML DOM - 针对HTML 文档的标准模型
- 核心DOM - 针对任何结构化文档的标准模型
-
核心DOM模型
- Document:文档对象
1.创建 1.window.document 2.document 可以省略window.2.方法 2.1获取Element对象 document.getElementById("id名称"):根据id属性值获取元素对象,id属性值一般唯一 document.getElementsByTagName("标签名称"):根据元素名称获取元素对象们, 返回值是一个数组 document.getElementsByClassName():根据class属性值获取元素对象们,返回值是数组 document.getElementsByName():根据name属性值获取元素对象们,返回值是数组 2.2创建其他DOM对象 document.createAttribute(name); document.createComment(); document.createElement(); document.createTextNode();- Element:元素对象
1.创建 通过document对象获取和创建 2.方法 setAttribute():设置元素的属性 removeAttribute)():移除元素属性给a标签设置和取消href的属性 <body> <a>click me!</a> <input id="btn1" type="button" value="设置a的属性"> <input id="btn2" type="button" value="取消a的属性"> <script> /* 1.创建 通过document对象获取和创建 2.方法 setAttribute():设置元素的属性 removeAttribute)():移除元素属性 */ //获得第一个a标签数组中的第一个a标签[0] var elementsByTagNameElement = document.getElementsByTagName("a")[0]; var elementById = document.getElementById("btn1"); elementById.onclick = function () { elementsByTagNameElement.setAttribute("href","https://www.baidu.com"); } var elementById1 = document.getElementById("btn2"); elementById1.onclick = function () { elementsByTagNameElement.removeAttribute("href"); } </script> </body>-
Node:节点对象
- 特点:所有DOM对象都可以被认为是一个节点
- 方法:CRUD dom树
- appendChild():向节点的子节点列表的结尾添加新的子节点
- removeChild():删除返回当前节点的指定子节点
- replaceChild():用新的节点替换一个节点
- 属性
- parentNode:返回父节点
-
ctrl+pidea中查看函数的参数类型 -
超链接的一个功能:
-
超链接变成按钮超链接功能: 1.可以被点击 2.点击之后,跳转到href指定的url需求 保留1功能,去除2功能,只有点击功能,没有跳转功能,就可以把超链接变成按钮实现 令href="javascript:void(0)"删除div1中的子节点div2<body> <div id="div1"> <div id="div2">div2</div> div1 </div> <a id="del1" href="javascript:void(0)">remove childNode</a> <script> var byId = document.getElementById("del1"); byId.onclick = function () { var div1 = document.getElementById("div1"); var div2 = document.getElementById("div2"); div1.removeChild(div2); } </script></body>
HTML DOM
-
1.标签体的设置和获取:innerHTML
-
使用HTML对象 的属性
-
控制元素样式
- 使用元素的style属性来设置
var div1 = document.getElementById("div1");//div也可以设置点击事件div1.onclick = function (){ div1.style.border = "20px solid red"; div1.style.width = "200px"; div1.style.fontSize = "20px"; //原本是font-size在这就变成了fontSize}- 提前定义好类选择器的样式,通过className属性来设置元素的class属性
<script> var div1 = document.getElementById("div1"); div1.onclick = function () { //通过设置标签的类,来控制样式 div1.className = "css的类名"; }</script>
事件
概念:某些组件被执行了某些操作之后,触发了某些代码的执行
-
事件:某些操作,如,单机,双击,键盘,鼠标悬浮,或移动
-
事件源:组件,如:按钮,文本输入框...
-
监听器:代码。
-
注册监听:将事件,事件源,监听器结合在一起,当事件源上发生了某个事件,则会触发执行某个监听器代码
- 获取html元素对象可以直接onclick,也就是说对象都有onclick对象
- 或者获取html元素对象之后,创建监听onclick函数
-
常见的监听事件
-
event对象,获取事件的具体内容
-
点击事件
- onclick,单击事件
- ondblclick,双击事件
-
焦点事件
- onblur,元素失去焦点,一般用于表单验证,验证用户名是否存在之类...
<script> document.getElementById("username").onblur = function () { alert("lose focus") } </script>- onfocus,元素获得焦点
-
加载事件
- onload:一张页面被加载完成后执行
window.onload = function (){ 在整个页面加载完成之后,执行此事件内的代码} -
鼠标事件
- onmousemove,鼠标被移动
- onmouseout,鼠标从某元素移开
- onmouseover,鼠标移到某元素之上
document.getElementById("username").onmouseover = function () { alert("mouse coming"); }- onmouseup,鼠标按键被松开
- onmousedown,鼠标按钮被按下
document.getElementById("username").onmousedown = function (event) { //当事件被监听到时,会给监听器传一个event对象 // 可以通过event获取相关事件具体信息 //鼠标左键是0,滚轮点击是1,右键点击时2 alert(event.button); } -
键盘事件
- onkeyup,某个键盘按键被松开
- onkeydown,某个键盘按键被按下
- onkeypress,某个键盘按键按下并松开
-
选择和改变
- onchange,域的内容被改变
- onselect,文本被选中
-
表单事件
- onsubmit,表单内的确认按钮被点击
- onreset,表单内的重置按钮被点击
-
案例
表单效验
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.div1{
margin: auto;
}
</style>
<script>
/*
1.给表单绑定submit事件,定义校验函数,分别校验各个input;
2.在监听器中调用各个input的效验函数,它们都会返回false或者true
3.如果全部input的效验函数都是true,监听器返回true,反之返回false
*/
window.onload = function ()
{
//给表单绑定submit事件,分别校验各个input,
var form1 = document.getElementById("form").onsubmit = function ()
{
//调用用户名效验方法,调用密码效验方法
return checkUsername() && checkPassword();
}
//给用户名和密码输入框分别绑定离开焦点的事件
document.getElementById("username").onblur = checkUsername;//切记等号右边是函数对象,不带()
document.getElementById("password").onblur = checkPassword;//切记等号右边是函数对象,不带()
}
function checkUsername (){
//获取用户名的值
let username = document.getElementById("username").value;
//定义正则表达式
let reg_name = /\w{6,12}/;//符号开始结束,6-12位
//判断值是否符合正则的规则
let s_username = document.getElementById("s_username");
if(reg_name.test(username))
{
s_username.innerHTML = "success";
return true;
}
else
{
s_username.innerHTML = "fail";
return false;
}
}
function checkPassword (){
//获取密码的值
let password = document.getElementById("password").value;
//定义正则表达式
let reg_password = /^\w{6,12}$/;//符号开始结束,6-12位
//判断值是否符合正则的规则
let s_password = document.getElementById("s_password");
if(reg_password.test(password))
{
s_password.innerHTML = "success";
return true;
}
else
{
s_password.innerHTML = "fail";
return false;
}
}
</script>
</head>
<body>
<div >
<form action="#" id="form" method="get" >
<table class="div1">
<tr>
<td><span>用户名</span></td>
<td>
<input type="text" name="username" id="username">
<!-- //返回表单效验的提示信息的-->
<span id="s_username" class="error"></span>
</td>
</tr>
<tr>
<td><span>密码</span></td>
<td>
<input type="password" name="password" id="password">
<!-- //返回表单效验的提示信息的-->
<span id="s_password" class="error"></span>
</td>
</tr>
<tr>
<td> <input type="submit" value="submit"></td>
</tr>
</table>
</form>
</div>
</body>
</html>
表单全选
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.xx01{
border: black solid 2px;
margin: auto;
}
tr,td,caption,th{
border: black solid 2px;
}
.trover
{
background: pink;
}
.trout
{
background: wheat;
}
</style>
<script>
/*
1.全选
获取所有的checkbox
遍历所有checkbox,使其变成选中状态,去查checkbox的属性,checked
*/
//1.在页面加载之后绑定事件
window.onload = function ()
{
//2.给全选按钮绑定单机事件
document.getElementById("allSelect").onclick = function ()
{
//1.获取所有的checkbox
var cbs = document.getElementsByName("cb");
for(var i = 0; i < cbs.length; i++)
{
//设置所有checkbox的状态和第一个一致,
// 也就是当前事件的事件源,表头的checkbox,可以使用this代替
cbs[i].checked = this.checked;
}
}
//3.给所有tr绑定鼠标移动事件
//遍历所有tr
var trs = document.getElementsByTagName("tr");
for(let i = 0; i < trs.length; i++)
{
trs[i].onmouseover = function ()
{
trs[i].className = "trover";
}
trs[i].onmouseout = function ()
{
trs[i].className = "trout"
}
}
}
</script>
</head>
<body>
<table class="xx01">
<caption>student infomation</caption>
<tr class="xx01">
<th><input type="checkbox" id="allSelect"></th>
<th>编号</th>
<th>姓名</th>
<th>性别</th>
<th>操作</th>
</tr>
<tr>
<td><input type="checkbox" name="cb"></td>
<td>1</td>
<td>zyc</td>
<td>male</td>
<td><a href="javascript:void(0);">del</a></td>
</tr>
<tr>
<td><input type="checkbox" name="cb"></td>
<td>2</td>
<td>zyc</td>
<td>male</td>
<td><a href="javascript:void(0);">del</a></td>
</tr>
<tr>
<td><input type="checkbox" name="cb"></td>
<td>3</td>
<td>zyc</td>
<td>male</td>
<td><a href="javascript:void(0);">del</a></td>
</tr>
</table>
</body>
</html>
BootStrap
响应式布局:同一套页面可以兼容不同分辨率的设备
快速入门:
- 下载BootStrap
- 在项目中将这三个文件夹复制
- 创建一个html页面,引入必要的资源文件
- css文件中
- .min.css是压缩的css文件
- .css是未压缩的css文件
基本模板html(css之类的文件夹都和src平级)
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link rel="stylesheet" href="../css/bootstrap.min.css">
</head>
<body>
<h1>你好,世界!</h1>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="../js/jquery-3.2.1.min.js" ></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="../js/bootstrap.min.js" ></script>
</body>
</html>
响应式布局
-
同一套页面可以兼容不同分辨率的设备
-
实现:依赖于栅格系统:将一行平均分成12个格子,可以去指定元素去占一个格子
-
步骤:
-
定义容器,相当于
标签- container:宽度固定,左右有留白
- container-fluid:沾满100%宽度
<!-- 定义容器--> <div class="container-fluid"> </div> -
定义行
,样式:row
<!-- 定义行--> <div class="row"> </div>- 定义元素,指定该元素在不同设备上,所占格子的个数,样式:col-设备代号-格子数目
- 设备代号
- xs:手机<768px
- sm:平板 >=768px
- md:中等屏幕:>=992px
- lg:大屏幕 >= 1200px
- 设备代号
<!-- 定义元素--> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div><!-- 定义容器--><div class="container-fluid"> <!-- 定义行--> <div class="row"> <!-- 定义元素--> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> <div class="col-lg-1 col-sm-2">col</div> </div></div>- 注意事项:
- 一行中如果,格子数目超过12,则超出部分自动换行
- 栅格类属性可以向上兼容,栅格类适用于屏幕宽度大于或等于分界点大小的设备(xs也可以在lg上正常显示)
- 如果当前访问设备宽度小于了设置栅格类属性的设备代码最小值,会一个元素沾满一整行
css样式和JS插件
全局 CSS 样式 · Bootstrap v3 中文文档 | Bootstrap 中文网 (bootcss.com)
一个标签属于两个类class
<div class="class1 class2"></div>全局css样式(可选的class很多详细可见,上面链接)
- 按钮
<button type="button" class="btn btn-default">(默认样式)Default</button>- 图片
响应式图片,图片随窗口变化<img src="..." class="img-responsive" alt="Responsive image">- 表格
<table class="table"></table>-
表单
-
导航条
-
分页条
-
轮播图
-
输入框居中显示
- col-md-offset-4 col-lg-offset-4 col-xl-offset-4
<div class="col-lg-4 col-md-offset-4 col-lg-offset-4 col-xl-offset-4" > <div class="input-group "> <input type="text" class="form-control" placeholder="Search for..."> <span class="input-group-btn"> <button class="btn btn-default" type="button">Go!</button> </span> </div><!-- /input-group --> </div>具体上面的网址,会复制根据自己需求修改即可。
Xml
-
概念:Extensible Markup Language 可扩展标记语言
- 可扩展:标签都是自定义的<自定义标签>
-
功能:
- 存储数据
- 配置文件
- 在网络中传输
- 存储数据
-
xml与html的区别
- xml的标签都是自定义的,html标签是预定义的
- xml语法严格,html语法松散
- xml用来存储数据,html用来展示数据
-
语法
-
基本语法
- xml第一行定义文档声明,注意必须是第一行,物理上的,放在第二行都不行的
<?xml version="1.0" encoding="ISO-8859-1"?>- xml中有且只有一个根标签
- 属性值必须使用引号引出,单双引号都可
- 标签必须有结束标签,类似于自闭合标签
可以不需要结束标签 - xml标签区分大小写
-
组成部分
- 文档声明
<?xml 属性1="xxx" 属性2="xxx" ?> version:版本号,1.0就行,必写的属性 encoding:编码方式,告知解析引擎当前文档使用的字符集,默认值:ISO-8859-1。当在idea中修改encoding属性时,idea会自动同步文件的编码,可以观察idea的右下角 standalone:是否独立(基本不使用) yes:不依赖其他文件 no:依赖其他文件-
指令(了解,当初设计XML的起初目的):结合css
-
标签:标签名称自定义
- 名称规则:
- 不以数字标点开头
- 不以xml Xml XML开头
- 名称规则:
-
属性
- id属性值唯一(得在约束文件中自己设置)
-
文本
- CDATA区:该区域的数据会被原样展示,避免了特殊符号的转义字符导致的阅读不畅
<![CDATA[ if(a > b && b < c) ]]><![CDATA[ 该中括号内的数据会被原样保存显示 ]]>
-
用户(程序员),软件使用者编写xml
-
软件(半成品-框架)本身解析xml
-
-
约束(规定xml文档的书写规则,能写什么标签)
-
作为框架的使用者要求
- 能够在xml中引用约束文档
- 简单读懂约束文档
-
分类
- DTD:一种简单的约束技术
- Schema:复杂约束技术
-
DTD(了解):
-
引入dtd文档到xml文档中
-
内部dtd:将约束规则定义在xml中
-
外部dtd:将约束规则定义在外部dtd文件中
- 本地
<!DOCTYPE 根标签名 SYSTEM "dtd文件的位置">- 网络
<!DOCTYPE 根标签名 PUBLIC "dtd文件的名字" "dtd位置 url类型">
-
-
-
Schema(能规定标签内的内容 .xsd)
- 引入.xsd文件
<?xml version="1.0" encoding="utf-8" ?> <根标签名 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xxx.cn/xml 文件名.xsd " xmlns:a="http://www.xxx.cn/xml"> <!--xsi:代表文件的位置,其中"http://www.xxx.cn/xml"代表生成的前缀namespace--> <!-- xmlns ns 代表namespace 命名空间--> <!-- xmlns:a 代表namespace 命名空间的简称为a,之后的所有便签都必须带有a:--> <a:user> </a:user> </根标签名>
-
-
解析:操作xml文档,将文档中的数据读取到内存中
- 操作xml文档
- 解析(读取):将文档数据读到内存中
- 写入,将内存中的数据保存到xml文档中,持久化的存储
- 解析xml的方式
- DOM:将标记语言文档一次性加载到内存,在内存中形成一棵DOM树(服务器端)
- 优点:操作方便,可以对文档进行CRUD的所有操作
- 缺点:占用过多内存
- SAX:逐行读取。基于事件驱动的(移动端)
- 优点:不占内存,只有一行
- 缺点:只能读取,不能增删改
- DOM:将标记语言文档一次性加载到内存,在内存中形成一棵DOM树(服务器端)
- xml的解析器:
- JAXP:sun公司提供的解析器。支持DOM和SAX两种思想(官方出品,必是垃圾,没人用)
- DOM4J:一款优秀的解析器
- Jsoup:本是解析HTML,也可以用来XML
- PULL:Android操作系统的内置解析器,sax方式的
- 操作xml文档
-
Jsoup:解析XML和HTML
- 下面代码中的
student.xml
<?xml version="1.0" encoding="UTF-8" ?> <students> <student number="0001"> <name id="1">zyc</name> <age>20</age> <sex>male</sex> </student> <student number="0002"> <name id="2">zyc01</name> <age>20</age> <sex>female</sex> </student> </students>- 使用步骤
- 导入jar包
- 获取Document对象,代表DOM树形结构
- 获取对应的标签,Element对象
- 获取对象的数据
public class JsoupDemo01 { public static void main(String[] args) throws IOException { //2.获取Document对象 //2.1获取student.xml的url路径 String path = JsoupDemo01.class.getClassLoader().getResource("student.xml").getPath(); //2.2解析xml文档,就是加载文档进入内存,获取DOM树 ---> Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //3.1获取元素对象,Elements是一个类继承了ArrayList Elements name = document.getElementsByTag("name"); for (Element element : name) { //3.2获取数据 // System.out.println(element.text()); } } } - 下面代码中的
-
对象的使用
- Jsoup:工具类,解析html或者xml文档,返回Document对象
parse:解析html或者xml文档,返回Document parse(File in, String charsetName):解析xml或者html文件的 parse(String html):直接解析html或者xml字符串的,一般不会使用 parse(URL url, int timeoutMillis):通过网络路径获取指定的html或者xml文档,常常用于爬虫技术 URL url = new URL("https://www.bilibili.com/"); Document document1 = Jsoup.parse(url, 10000);//timeoutMillis是超时时间毫秒 System.out.println(document1.text()); System.out.println(document1);- Document:文档对象,代表内存中的DOM树
通过Document对象获取Element对象 getElementsByTag(String TagName):根据标签名称获取元素的集合 getElementsByAttribute(String Key):根据属性名称获取对象集合 getElementsByAttributeValue(String key, String Value):根据对应的属性名和属性值获取元素对象集合public class JsoupDemo02 { public static void main(String[] args) throws IOException { //获取student.xml的path String path = JsoupDemo02.class.getClassLoader().getResource("student.xml").getPath(); //获取Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //获取所有的元素对象 //获取所有student对象 Elements elements = document.getElementsByTag("student"); System.out.println(elements); System.out.println("------------------------"); //获取属性名为id的对象们 Elements elements1 = document.getElementsByAttribute("id"); System.out.println(elements1); System.out.println("------------------------"); //获取 number属性值为0001的元素对象 Elements elements2 = document.getElementsByAttributeValue("number", "0001"); System.out.println(elements2); System.out.println("------------------------"); //获取 id值为1的元素对象 Element element = document.getElementById("1");//属性名称必须是id才能用这个函数 System.out.println(element); } }-
Elements:元素Element对象的集合,可以当做ArrayList
来使用 -
Element:元素对象
获取Element的子元素对象 getElementsByTag(String TagName):根据标签名称获取元素的集合 getElementsByAttribute(String Key):根据属性名称获取对象集合 getElementsByAttributeValue(String key, String Value):根据对应的属性名和属性值获取元素对象集合获取属性值 String attr(String key):根据属性名称获取属性值获取文本内容 String text():所有子标签的纯文本内容获取innerHTML String html():获取标签体的所有内容(包括子标签的字符串内容)- Node:节点对象
- 是Document和Element的父类
-
快捷查询方式
- selector:选择器
- Elements select(String cssQuerry);
public class JsoupDemo04 { public static void main(String[] args) throws IOException { //获取student.xml的path String path = JsoupDemo04.class.getClassLoader().getResource("student.xml").getPath(); //获取Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //查询name标签 Elements elements = document.select("name"); System.out.println(elements); //查询id为1的标签元素,id:用#+id的值 System.out.println("----------------------------------"); Elements elements1 = document.select("#1"); System.out.println(elements1); System.out.println("----------------------------------"); //获取student标签并且number属性值为0001的age子标签 Elements elements2 = document.select("student[number='0001'] > age"); System.out.println(elements2); } }- XPath:即为XML路径语言,它是一种用来确定xml文档中某部分位置的语言
- 使用Jsoup的Xpath需要导入额外jar包:JsoupXpath
- 查询w3cshool参考手册,使用xpath的语法来查询
public class JsoupDemo05 { public static void main(String[] args) throws IOException, XpathSyntaxErrorException { //获取student.xml的path String path = JsoupDemo05.class.getClassLoader().getResource("student.xml").getPath(); //获取Document对象 Document document = Jsoup.parse(new File(path), "utf-8"); //根据document创建JXDocument对象 JXDocument jxDocument = new JXDocument(document); //结合xpath语法查询 //查询student标签内的所有子标签 List<JXNode> jxNodes = jxDocument.selN("//student");//返回Node; for (JXNode jxNode : jxNodes) { System.out.println(jxNode.getElement().text()); } System.out.println("-----------------------------------------"); //查询student标签内的所有name List<JXNode> jxNodes1 = jxDocument.selN("//student/name");//返回Node; for (JXNode jxNode : jxNodes1) { System.out.println(jxNode.getElement().text()); } //查询student标签下的带有id属性的name标签 System.out.println("-----------------------------------------"); List<JXNode> jxNodes2 = jxDocument.selN("//student/name[@id]");//返回Node; for (JXNode jxNode : jxNodes2) { System.out.println(jxNode.getElement().text()); } //查询student标签下的带有id属性的name标签,且id=1 System.out.println("-----------------------------------------"); List<JXNode> jxNodes3 = jxDocument.selN("//student/name[@id='1']");//返回Node; for (JXNode jxNode : jxNodes3) { System.out.println(jxNode.getElement().text()); } } } - selector:选择器
web回顾
- 软件架构
- C/S
- B/S
- 资源分类
- 静态资源:html,css,js,所有用户访问得到的结果都是一样的,静态资源可以直接被浏览器解析
- 动态资源:servlet,jsp,asp每个用户访问相同资源得到结果可能不一样。动态资源被转换为静态资源之后才能被浏览器所解析
- 请求 - 响应
- 网络通信三要素
- IP:电子设备在网络中的唯一标识
- 端口:应用程序在计算机中的唯一标识。0 ~ 65536
- 传输协议:规定了数据传输的规则
- tcp:安全协议,三次握手
- udp:不安全协议,速度较快
web服务器软件
- 服务器:安装了服务器软件的计算机
- 服务器软件:接受用户的请求,处理请求,做出响应
- web服务器软件:接受用户的请求,处理请求,做出响应
- 在web服务器软件中,可以部署web项目,让用户通过浏览器来访问这些项目
- web容器也称为web服务器,因为这些动态资源只能在web容器中运行
- 常见的java服务器软件
- webLogic:oracle公司,大型JavaEE服务器,支持所有JavaEE规范,收费。
- webSphere:IBM公司,与webLogic类似
- JBOSS:和webLogic类似
- Tomcat:Apache基金组织,中小型的JavaEE服务器,仅仅支持少量的JavaEE规范
- JavaEE:Java语言在企业级开发中使用的技术规范和总和,一共规定了13项的规范
Tomcat
- 下载
- Apache Tomcat® - Welcome!
- Tomcat -8-Core-64-bit-Windows zip
- 安装
- 解压压缩包即可
- 安装目录不要有中文
- 卸载
- 删除目录即可?
- 启动
- 启动\bin\startup.bat (一般都在idea启动,所以就不会启动黑窗口,如果都启动就会造成端口被占用)
- 黑窗口一闪而过:
- 原因:没有正确配置JAVA_HMOE环境变量
- bat文件就是一批windows的dos命令
- 启动报错:端口号被占用了
- idea不需要开启黑窗口,如果开了黑窗口,就会导致端口号被占用,此种情况更改和杀死进程都是不行的
- 关闭
- 正常关闭:
- \bin\shutdown.bat
- 在黑窗口输入 ctrl + c
- 强制关闭:点击窗口关闭按钮
- 正常关闭:
- 配置
- 部署项目的方式
- 直接将web项目放到webapps即可
- localhost\项目名,其中项目名也称虚拟路径
- 将项目打包成war包,再将war包放到webapps,war会自动解压缩
- 配置conf\server.xml文件,在
标签体中配置 (不安全,可能会破坏配置文件) - docBase:项目存放位置
- path:项目的虚拟目录
- 在conf\Catalina\localhost创建任意名称的xml文件。在文件中编写
,现在的虚拟目录就是xml的文件名称,所以path参数可以省略 - localhost/xml文件名/资源文件
- 热部署,推荐
- 直接将web项目放到webapps即可
- 静态项目和动态项目
- 目录结构
- java动态项目目录结构
- 项目的根目录
- WEB-INF目录
- web.xml:web项目的核心配置文件(之后学习中,可以没有xml此文件)
- classes目录:放置字节码文件
- lib目录:放置依赖的jar包
- WEB-INF目录
- 项目的根目录
- java动态项目目录结构
- 目录结构
- 部署项目的方式
- tomcat目录结构
- bin:可执行文件
- conf:配置文件
- lib:依赖的jar包
- logs:日志文件
- temp:临时文件
- webapps:存放web项目的地方
- work:存放运行时的数据
- 将Tomcat集成到idea中,并且创建JavaEE项目,部署项目
- 在编辑配置-部署-里面设置虚拟路径
- 访问
http://localhost:8080/webLean02_war_exploded/资源文件(其中webLean02_war_exploded为默认虚拟路径) - 在编辑配置-执行更新和框架停用选项更改为->当更新资源时,这样每当更新资源之后,就不用重启服务器了
- 创建web项目,在idea中(新版本2021.之后)
- new project
- 选择Java Enterprise,配置应用服务器程序为系统的tomcat,可以设置工件,和包目录
- 下一步,会让选择JavaEE的版本,规范和实现(目前不懂什么意思)
- 因为新版idea没有webApplication选项了,所以创建web项目和之前有所差别
Servlet
- 概念:server + applet 运行在服务器端的接口
- servlet就是一个接口,定义了Java类被浏览器(tomcat)访问到的规则(接口)
- 自定义一个类实现Servlet接口,复写方法
快速入门
- 创建JavaEE项目
- 定义一个类,实现Servlet接口
- 实现接口中的抽象函数
- 配置Servlet(在web.xml文件配置,在
根标签内写入如下代码)
<!--配置Servlet--> <!-- <servlet-name>里的名字随便写--> <!-- <servlet-class>是实现Servlet接口的全类名,包括包名--> <servlet> <servlet-name>demo01</servlet-name> <servlet-class>com.example.web.servlet.ServletDemo01</servlet-class> </servlet> <!-- <servlet-mapping>实现servlet的映射--> <servlet-mapping> <servlet-name>demo01</servlet-name> <url-pattern>/demo01</url-pattern> </servlet-mapping> <!--http://localhost:8080/webLean02_war_exploded/demo01-->servlet执行原理
- 当服务器接受到客户端浏览器的请求后,会解析请求的URL路径,获取访问Servlet的资源路径(如上文的/demo01)
- 查找web.xml文件,是否有对应的
标签体内容。 - 如果有,再找到
全类名 - tomcat会将上一条对应的类的字节码文件加载进内存,并创建对象
- 调佣其重写的方法
servlet生命周期
- 创建:执行init方法,只执行一次
- 默认情况下,第一次访问,Servlet被创建
- 可以在配置中设置Servlet的创建时机
- 在
标签下设置 - 第一次访问时,创建
的值是负数
- 在服务器启动时,创建
的值为0或正数
- 第一次访问时,创建
- 在
- servlet的init方法,只执行一次,说明一个servlet在内存中只存在一个对象,servlet是单例的
- 多个用户访问时,可能出现线程安全问题
- 解决 方法:尽量不要在servlet定义成员变量,即使定义也不要赋值(不懂)
- 提供服务:执行service()方法,执行多次
- 每次访问Servlet时,Service都会被调用一次
- 销毁
- Servlet被销毁时执行,服务器关闭时,Servlet被销毁
- 只有服务器正常关闭时,才会调用destroy方法
- destroy方法在Servlet被销毁之前执行,一般用于释放资源
@Override public void init(ServletConfig servletConfig) throws ServletException { //在servlet创建时,会被执行一次 } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { //每一次servlet被访问时,都会执行该方法。 } @Override public void destroy() { //析构方法,在servlet被关闭(服务器关闭),执行一次。 }一般不会实现这两个方法 @Override public ServletConfig getServletConfig() { return null; } @Override public String getServletInfo() { return null; }servlet3.0支持注解配置
- 支持注解配置(就是说不用向web.xml里面写配置了)
- 以后项目中可能需要很多个servlet实现类,如果都向web.xml里面写,就会很烦,所以出现了注解
- 在类上面使用注解@webservlet
@WebServlet(name = "helloServlet", value = "/资源路径",urlPatterns = " /资源路径") name:servlet的name,可以省略,没用因为不需要配置web.xml urlPatterns : "/资源路径" value:是注解中最重要的属性,当注解中只有一个实参时,默认认为是urlPatterns,并且"value="可以省略 最终写法:@WebServlet( "/资源路径")idea和tomcat的相关配置
-
idea会为每一个tomcat部署的项目,创建一个配置文件
- 查看控制台输出查看配置文件的位置:
UsingCATALINA_BASE: C:\Users\26893\AppData\Local\JetBrains\IntelliJIdea2021.1\tomcat\b6a8cb35-f8fd-4007-abd6-ab7215a29cec \conf\Catalina\localhost\webLean02_war_exploded里面的内容如下 ` <Context path="/webLean02_war_exploded" docBase="D:\Code_Note\Java_project\webLean02\target\webLean02-1.0-SNAPSHOT" /> ` -
存储项目的位置:分为 工作空间项目 和 tomcat部署的web项目
- tomcat真正访问的是tomcat部署的web项目,其对应着工作空间的out目录下的资源
- WEB-INF目录下的资源,不能被浏览器直接访问,也就是不要把资源放到WEB-INF目录下
- 端点调试,设置端点,点击debug虫子图标调试
servlet体系结构
-
出错了,去看tomcat日志logs
-
servlet -- 接口
- |
- GenericServlet -- 抽象类
- |
- HttpServlet -- 抽象类
-
GenericServlet :将Servlet接口方法做了默认空的实现,只将service方法作为抽象
- 将来定义servlet类时,可以继承GenericServlet,实现service()方法即可
- 需要其他方法时,只需复写即可
-
HttpServlet:对Http协议的封装,简化操作
- 定义类,继承HttpServlet
- 复写doGet,或者doPost方法
servlet的相关配置
- urlPattern:servlet的访问路径
- @WebServlet("/xxxx")
- @WebServlet({"/a","/b","/c"}):一个servlet定义多个访问路径
- /a,/b,/c都可以访问到此Servlet
- 路径的定义规则
- /xxx
- /xxx/xxx:多层路径,目录结构
- *.do:
*是通配符的意思,前面不加/,其中.do中的do可以是任何字符,比如*.xxx
HTTP协议:请求消息
概念:Hyper Text Transfer Protocol 超文本传输协议
- 传输协议:定义了客户端和服务器端传送数据的格式
- 特点:
- 基于TCP/IP的高级协议
- 默认端口号:80
- 基于请求/响应模型的,一次请求对应一次响应
- 无状态的协议:每次请求之间相互独立,不能去交互数据
- 历史版本
- 1.0:每一次请求响应,都会创建新的连接
- 1.1:复用连接
- 彩蛋:在www.baidu.com的控制台上有百度的校招广告。
- 请求消息数据格式
- 请求行
- 请求方式 请求url 请求协议/版本
- GET /xxx.html HTTP/1.1
- 请求方式:有7种,常用的有两种
- POST:
- 请求参数在请求体中
- 请求的url长度没有限制
- 安全性相对
- GET:
- 请求参数在请求中,也就是url
- 请求的url长度有限制
- 安全性不高,因为参数在url上
- POST:
- 请求头:客户端浏览器告诉服务器的一些信息
- 请求头名称 : 请求头值,键值对形式
- 常见的请求头:
- User-Agent:浏览器向服务器传输浏览器的信息
- 可以在服务器端获取该请求头信息,解决浏览器的兼容问题
- Accept:告诉服务器可以响应的格式 html xml ...
- Referer:告诉服务器,当前请求从哪里来?
- 作用
- 防止盗取链接
- 统计工作
- 作用
- User-Agent:浏览器向服务器传输浏览器的信息
- 请求空行
- 就是一个空行,分隔POST的请求头和请求体的
- 请求体(正文,请求参数)
- GET:
- get方式没有请求体
- POST:
- 参数名=参数值
- username=zyc
- GET:
- 请求行
- 响应消息数据格式
Request
-
request和response对象的原理
- request对象和response对象是由服务器创建的,而程序员是使用者
- request对象是来获取请求消息的,response对象是用来设置相应消息的
-
request对象继承体系结构
- ServletRequest -- 接口
- | 继承
- HttpServletRequest -- 接口
- | 实现
- org.apache.catalina.connector.RequestFacade@53892c56 类(由tomcat服务器实现)
-
request功能:
-
获取请求消息数据
-
获取请求行数据
- GET /web01/demo1?name=xxx HTTP/1.1(请求行的一个例子)
- 方法:
- 获取请求方式:GET - String getMethod() - (重点) 获取虚拟目录:/web01 - String getContextPath() - 获取Servlet路径:/demo1 - String getServletPath() - 获取GET方式的请求参数:name=xxx - String getQueryString() - (重点)获取请求URI:/web01/demo1 - String getRequestURI():/web01/demo1 - String getRequestURL():http://localhost/web01/demo1 URL:统一资源定位符 URI:统一资源标识符 - 获取协议和版本:HTTP/1.1 - String getProtocol() - 获取客户机的ip地址: - String getRemoteAddr()- 动态获取虚拟目录
- 当虚拟路径改变时,写死的虚拟路径(字符串常量)需要一个个修改,很不智能,所有需要动态获取虚拟路径,当虚拟路径改变时,程序自动通过
getContextPath即可变更虚拟路径,直到之后学到getContextPath之前都是写死的虚拟路径。
- 当虚拟路径改变时,写死的虚拟路径(字符串常量)需要一个个修改,很不智能,所有需要动态获取虚拟路径,当虚拟路径改变时,程序自动通过
-
获取请求头数据
- (重点)String getHeader(String name):通过请求头的名称获取请求头的值
- Enumeration
getHeadNames():获取所有请求头的名称,返回值是迭代器类型
Enumeration<String> headerNames = request.getHeaderNames();while(headerNames.hasMoreElements()){ String name = headerNames.nextElement(); System.out.println(name+"----"+request.getHeader(name));}//通过user-agent判断浏览器是否是chrome String header = request.getHeader("user-agent"); if(header.contains("Chrome")) { System.out.println("google"); } -
获取请求体数据
-
请求体:只有POST才有请求体,在请求体中封装了POST的请求参数
- 获取流对象
BufferedReader reader = request.getReader();//获取字符输入流,只操作字符数据 ServletInputStream inputStream = request.getInputStream();//获取字节输入流,可以操作所有类型数据 //在文件上传的知识点之后讲解- 再从流对象获取数据
//获取post方式的请求体 @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取请求消息体 BufferedReader reader = request.getReader(); //读取数据 String line = null; while((line = reader.readLine()) != null) { System.out.println(line); } }
-
-
-
其他功能
-
获取请求参数通用方式(get方法的请求参数在请求行,post的请求参数在请求体,故获取方式不同)
- GET:String getQueryString()
- POST:BufferedReader getReader()
- 通用方法:兼容POST和GET方法的获取请求参数
- 获取请求参数的值
根据参数名称获取参数值String parameter = request.getParameter(String name); 根据参数名获取参数值得数组,hobby=xx&hobby=xxx,多用于复选框。String[] parameterValues = request.getParameterValues(String name); 获取所有请求的参数名称Enumeration<String> parameterNames = request.getParameterNames(); 获取所有参数的map集合Map<String, String[]> parameterMap = request.getParameterMap();@WebServlet(name = "Servletdemo02", value = "/Servletdemo02") public class Servletdemo02 extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("GET---"); //获取根据参数名称获取参数的值 String username = request.getParameter("username"); System.out.println(username); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request,response);//因为是通用写法,所有POST方法,就可以调用GET方法 } }主要是看看Map的遍历方法 Map<String, String[]> parameterMap = request.getParameterMap(); //获取所有键 Set<String> name = parameterMap.keySet(); for (String string : name) { String[] values = parameterMap.get(string); for (String s : values) { System.out.println(s); } }-
解决中文乱码问题
-
GET方式,中文不会乱码
-
POST方式会乱码
- 因为POST方式,是通过流的方式获取请求参数的,所以需要设置流的编码
request.setCharacterEncoding("html内的编码格式");
-
-
请求转发:一种在服务器内部的资源跳转方式
-
1.步骤:
- 1.通过request对象获取请求转发器对象:
RequestDispatcher requestDispatcher = request.getRequestDispatcher(String path);//path是@WebServlet里的Servlet的路径- 2.使用RequestDispatcher对象进行转发:
requestDispatcher.forward(ServletRequest servletRequest,ServletResponse servletResponse );- 简化代码,使用链式编写方式就是
request.getRequestDispatcher("/Servletdemo03").forward(request,response); -
特点:
- 资源路径(浏览器地址栏)没有发生变化
- 只能转发访问当前服务器内部资源中
- 转发仅仅是一个请求,尽管访问了多个资源文件
-
-
共享数据:
- 域对象:一个有作用范围的对象,可以在范围内去共享数据
- request的域:一次请求的范围,一般用于请求转发的多个资源中共享数据
- 方法
void request.setAttribute(String name, Object obj):存储数据 Object request.getAttribute(String name):通过键获取数据 void removeAttribute(String name):通过键移除键值对- 注意请求转发的代码要在request.setAttribute之后,否则就会转发到的servlet的getattribute是null
request.setAttribute("msg","hello"); request.getRequestDispatcher("/Servletdemo03").forward(request,response); -
获取ServletContext
ServletContext servletContext = request.getServletContext();
-
-
案例分析
案例1登录
- 步骤
- 导入需要的jar包,注意到导入到-web-inf-libs,这样tomcat才能识别到
- mysql connector
- Spring JDBC
- durid
- servlet
- 创建数据库的环境
- 创建包com.zyc.domain,创建user类
- 创建com.zyc.dao,创建userDao类,DAO(Data Access Object)
- 编写com.zyc.web.servlet.LoginServlet类
- login.html中form表单action的路径写法
- 虚拟目录+/servlet路径
- 注意点:
- 我上面写的mysql驱动配置文件(durid.properties)适配8以上的mysql驱动包
ctrl + alt + t快捷键环绕 try catch- 出现500访问错误,解决办法,把lib里文件夹放到WEB-INF目录下,要不然tomcat找不到
- 还出现个错误,就是接受参数,创建user对象,设置password时,调用了
setUsername,导致密码是账户是密码,密码为空,属于马虎错误 - 出现405错误,当我把servlet里doget和dopost方法默认创建的
super.doPost(req, resp)删掉就好了,你信吗,反正我是好了。
- 导入需要的jar包,注意到导入到-web-inf-libs,这样tomcat才能识别到
项目结构
- 生成项目结构方法
- 右键模块,找到在终端打开,输入
tree /f;,采用这种方法,如果使用图片主要是导入此文件到别的地方,可能会找不到资源
- 右键模块,找到在终端打开,输入
│ pom.xml │ web03.iml │ ├─lib │ druid-1.1.10.jar │ mysql-connector-java-8.0.24.jar │ protobuf-java-3.11.4.jar │ spring-beans-5.1.5.RELEASE.jar │ spring-core-5.1.5.RELEASE.jar │ spring-jcl-5.1.5.RELEASE.jar │ spring-jdbc-5.1.5.RELEASE.jar │ spring-tx-5.1.5.RELEASE.jar │ ├─src │ │ druid.properties │ │ │ ├─main │ │ ├─java │ │ │ └─com │ │ │ └─zyc │ │ │ ├─dao │ │ │ │ UserDao.java │ │ │ │ │ │ │ ├─domain │ │ │ │ User.java │ │ │ │ │ │ │ ├─test │ │ │ │ UserDaoTest.java │ │ │ │ │ │ │ ├─utils │ │ │ │ JDBCUtils.java │ │ │ │ │ │ │ └─web │ │ │ └─servlet │ │ │ failServlet.java │ │ │ LoginServlet.java │ │ │ successServlet.java │ │ │ │ │ ├─resources │ │ └─webapp │ │ │ index.jsp │ │ │ login.html │ │ │ │ │ └─WEB-INF │ │ │ web.xml │ │ │ │ │ └─lib │ │ druid-1.1.10.jar │ │ mysql-connector-java-8.0.24.jar │ │ protobuf-java-3.11.4.jar │ │ spring-beans-5.1.5.RELEASE.jar │ │ spring-core-5.1.5.RELEASE.jar │ │ spring-jcl-5.1.5.RELEASE.jar │ │ spring-jdbc-5.1.5.RELEASE.jar │ │ spring-tx-5.1.5.RELEASE.jar │ │ │ └─test │ ├─java │ └─resources └─target ├─classes │ │ druid.properties │ │ │ └─main │ ├─java │ │ └─com │ │ └─zyc │ │ ├─dao │ │ │ UserDao.class │ │ │ │ │ ├─domain │ │ │ User.class │ │ │ │ │ ├─test │ │ │ UserDaoTest.class │ │ │ │ │ ├─utils │ │ │ JDBCUtils.class │ │ │ │ │ └─web │ │ └─servlet │ │ failServlet.class │ │ LoginServlet.class │ │ successServlet.class │ │ │ └─webapp │ │ index.jsp │ │ login.html │ │ │ └─WEB-INF │ web.xml │ ├─generated-sources │ └─annotations └─web03-1.0-SNAPSHOT │ index.jsp │ login.html │ ├─META-INF │ MANIFEST.MF │ └─WEB-INF │ web.xml │ ├─classes │ │ druid.properties │ │ │ └─main │ ├─java │ │ └─com │ │ └─zyc │ │ ├─dao │ │ │ UserDao.class │ │ │ │ │ ├─domain │ │ │ User.class │ │ │ │ │ ├─test │ │ │ UserDaoTest.class │ │ │ │ │ ├─utils │ │ │ JDBCUtils.class │ │ │ │ │ └─web │ │ └─servlet │ │ failServlet.class │ │ LoginServlet.class │ │ successServlet.class │ │ │ └─webapp │ │ index.jsp │ │ login.html │ │ │ └─WEB-INF │ web.xml │ └─lib druid-1.1.10.jar hamcrest-core-1.3.jar junit-4.12.jar mysql-connector-java-8.0.24.jar protobuf-java-3.11.4.jar spring-beans-5.1.5.RELEASE.jar spring-core-5.1.5.RELEASE.jar spring-jcl-5.1.5.RELEASE.jar spring-jdbc-5.1.5.RELEASE.jar spring-tx-5.1.5.RELEASE.jaruserDao
package main.java.com.zyc.dao; import main.java.com.zyc.domain.User; import main.java.com.zyc.utils.JDBCUtils; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; /** * 操作数据库中user表 的类 */ public class UserDao { // 声明JDBCTemplate对象公用 private JdbcTemplate jdbcTemplate = new JdbcTemplate(JDBCUtils.getDataSource()); /** * 登录方法 * @param loginUser,只有用户名和密码 * @return 返回包括用户的所有信息 */ public User login(User loginUser) { try { //编写sql String sql = "select * from user where username = ? and password = ?"; //调用query方法 User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), loginUser.getUsername(), loginUser.getPassword()); return user; } catch (DataAccessException e) { e.printStackTrace(); return null; } } }user
package main.java.com.zyc.domain; /** * 用户的实体类 * */ public class User { private int id; private String username; private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override//方便测试 public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } }JDBCUtils
package main.java.com.zyc.utils; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; /** * JDBC工具类 * 使用Druid连接池 */ public class JDBCUtils { private static DataSource dataSource; static { try { //加载配置文件,初始化连接池对象 Properties pro = new Properties(); //使用ClassLoader加载配置文件,获取字节输入流 InputStream resourceAsStream = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"); pro.load(resourceAsStream); //初始化连接池对象 dataSource = DruidDataSourceFactory.createDataSource(pro); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * 获取连接池对线 * @return */ public static DataSource getDataSource() { return dataSource; } /** * 获取连接对象 * @return * @throws SQLException */ public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } }failServlet
package main.java.com.zyc.web.servlet; import main.java.com.zyc.dao.UserDao; import main.java.com.zyc.domain.User; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/failServlet") public class failServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置编码 resp.setContentType("text/html;charset=utf-8"); //输出 resp.getWriter().write("fail wrong username and psw"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req,resp); } }LoginServlet
package main.java.com.zyc.web.servlet; import main.java.com.zyc.dao.UserDao; import main.java.com.zyc.domain.User; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/LoginServlet") public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置编码 req.setCharacterEncoding("utf-8"); //获取请求参数 String username = req.getParameter("username"); String password = req.getParameter("password"); //封装user对象 User loginUser = new User(); loginUser.setUsername(username); loginUser.setPassword(password); //调用UserDao的login方法 UserDao userDao = new UserDao(); User resUser = userDao.login(loginUser); //判断user if(resUser == null) { //登录失败 req.getRequestDispatcher("/failServlet").forward(req,resp); } else { //登录成功 req.setAttribute("user",resUser); req.getRequestDispatcher("/successServlet").forward(req,resp); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req,resp); } }successServlet
package main.java.com.zyc.web.servlet; import main.java.com.zyc.domain.User; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet("/successServlet") public class successServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取request域中共享的对象 User user = (User) req.getAttribute("user"); //设置编码 resp.setContentType("text/html;charset=utf-8"); //输出 if(user != null){ resp.getWriter().write("success!"+user.getUsername()+" welcome"); } else { resp.getWriter().write("null pointer"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req,resp); } }BeanUtils工具类
- 导入jar包
// //获取请求参数 // String username = req.getParameter("username"); // String password = req.getParameter("password"); // // //封装user对象 // User loginUser = new User(); // loginUser.setUsername(username); // loginUser.setPassword(password); 将上面的代码,获取参数,封装对象的操作,使用BeanUtils优化成如下代码 //获取所有请求参数 Map<String, String[]> parameterMap = req.getParameterMap(); //创建一个user对象 User loginUser = new User(); //使用BeanUtils封装 try { BeanUtils.populate(loginUser,parameterMap); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); }- 用于封装JavaBean
- JavaBean:标准的Java类
- 类必须被public修饰
- 必须提供空参的构造器
- 成员变量必须使用private修饰
- 提供public的setter和getter方法
- 一般放在domain包内
- JavaBean功能:封装数据
- 方法:
- serProperty(bean,属性名,属性值)
- getProperty(bean,属性名)
- populate(Object bean,Map map):将map集合的键值对信息,封装到对应的JavaBean对象中
- JavaBean:标准的Java类
HTTP协议:响应消息
- 请求消息:客户端发送给服务器端的数据
- 数据格式
- 请求行
- 请求头
- 请求空行
- 请求体
- 数据格式
- 响应消息:服务器端发送给客户端的数据
- 数据格式
- 响应行
- 组成:协议 / 版本 响应状态码 状态码描述
- 响应状态码:服务器告诉客户端浏览器本次请求响应的状态
- 1xx:服务器接受客户端消息,但没有接受完成,等待一段时间后,发送1xx状态码
- 2xx:成功。200
- 3xx:重定向。302(重定向),304(访问缓存,图片缓存到本地,再次访问从本地缓存获取)
- 4xx:客户端出现错误
- 404(请求路径没有对应的资源)
- 405(请求方式没有对应的doXXX方法
- 5xx:服务器端出现错误
- 500(服务器端内部代码出现异常)
- 响应头
- 格式:头名称:头的值
- 常见的响应头:
- Context-Type:服务器告诉客户端本次响应体数据格式以及编码格式
- Context-Length:响应体长度
- Context-disposition:服务器告诉客户端以什么方式打开响应体数据
- 默认值:in-line,在当前页面打开
- attachment;filename=xxx:以附件形式打开响应体。用于文件下载
- 响应空行
- 响应体
- 真实传输的数据(图片二进制,html代码)
- 响应行
- 数据格式
- Response对象
- 设置响应消息
- 设置响应行
- 格式:HTTP/1.1 200 OK
- 设置状态码:
setStatue(int sc)
- 设置响应头
setHeader(String name, String value)
- 设置响应体
- 获取输出流
- 字符输出流:只能输出字符数据
PrintWriter getWriter()
- 字节输出流:输出任意数据
ServletOutputStream getOutputStream()
- 字符输出流:只能输出字符数据
- 使用输出流将数据输出到浏览器中
- 获取输出流
- 设置响应行
- 设置响应消息
案例
完成重定向
- 原理式重定向方法
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //访问response01会自动跳转到response02资源 System.out.println("01........"); //设置状态码为302 response.setStatus(302); //设置响应头location response.setHeader("location","/web02/response02"); }- 简化式重定向方法(简单方法)
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //访问response01会自动跳转到response02资源 response.sendRedirect("/web02/response02"); }-
重定向的特点
redirect- 重定向的地址栏发生变化
- 重定向可以访问其他站点(服务器)的资源
- 重定向是两次请求(*),两次请求意味着不能使用一个request对象共享数据
-
请求转发的特点
forward- 转发地址栏路径不变
- 转发只能访问当前服务器下的资源
- 转发是一次请求(*),一次请求意味着可以使用一个request对象共享数据
路径的写法
- 路径的写法:
- 分类
- 相对路径:
./index.jsp,相对的文件夹路径。../index.jsp - 绝对路径:通过绝对路径可以确定唯一资源
- 如:
http:localhost:8080/虚拟路径/资源文件,省略http:localhost:8080->/虚拟路径/资源文件 - 给客户端用(请求从客户端来,点击客户端的请求):加虚拟路径
/虚拟路径/资源文件 - 给服务器用(请求从服务器端来,从servlet->servlet):不加虚拟路径
/资源文件- 请求转发,是给服务器使用的
- 如:
- 相对路径:
- 分类
(*)动态获取虚拟目录,前面的虚拟路径都需改成动态获取
//动态获取虚拟目录 String contextPath = request.getContextPath(); response.sendRedirect(contextPath + "/response01");
服务器输出字符数据到浏览器
服务器输出字节数据到浏览器
验证码
ServletContext对象
概念:代表整个web应用,可以和程序的容器(服务器)进行通信交互
案例 - 文件下载
-
-
浙公网安备 33010602011771号