文章目录
前言
经过几十天的学习,终于算是看完了一部课程,还是边学边玩,真的又浪费了时间,往后努力吧!!!
由于感觉自己javaweb知识点感觉很薄弱决定先不学框架,先看一套基础课程,选择的是B站的黑马程序员JavaWeb全套教程,现在也算看完了,总结一下,以免后面忘记,也方便以后回顾,现在已经感觉到前面的忘完了,借此机会也巩固一下总体的知识点,黑马课程的资料https://pan.baidu.com/s/1LxIxcHDO7SYB96SE-GZfuQ 提取码:dor4
最后的黑马路有网项目在github上有,可以自己检索,这里挂一个和视频差不多的.
知识点梳理
按自己的java项目梳理
【day01】
Reflect反射
通过后面的学习确实感觉到了反射的重要性,真的是框架的灵魂,在BaseServlet中已经被其折服,后面有机会一定要重新重点掌握一下
/**
* 反射:框架的灵魂
* *将类的各个组成部分封装成其他对象,这就是反射
* 优点:1.可以在程序运行过程中,操作这些对象
* 2.可以解耦,提高程序可扩展性
*
* 使用时需要获得Class对象, 方式
* 1.Class.forName("全类名"):将字节码文件加载进内存,返回class对象
* 2.类名.class:通过类名的属性class获取
* 3.对象.getClass():getClass()方法在object类中定义着
*/
/**使用class功能(大部分为获取功能)
* 1.获取成员变量s
* getFields()
* getField(String name)
*
* getDeclaredFileds()
* getDeclaredFiled(String name)
* 2.获取构造方法s
* Constructor<?> getConstructors()
* Constructor<T> getConstructor(类<?>...parameterTypes)
* Constructor<?> getDeclaredConstructors()
* Constructor<T> getDeclaredConstructor(类<?>...parameterTypes)
* 3.获取成员方法s
* getMethods("方法名",parameterTypes);
* Method执行方法:Method.invoke(类,parameterTypes);
* Method获取方法名称:getName()
* 4.获取类名
* getClassName()
*/
Person p = new Person();
System.out.println("修改私有变量");
Field d = pClass.getDeclaredField("age");
d.setAccessible(true);//忽略访问权限修饰符的安全检查//暴力反射
/**
* "框架"案例
* 编写一个"框架",在不更改代码的前提下,实现创建任意对象,执行任意方法
*
* 需要使用配置文件
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
//1.加载配置文件
Properties pro =new Properties();
//获取类加载器,用类的字节码文件(class)
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
//2.获取配置文件数据
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3.加载类进内存
Class cls = Class.forName(className);
Object obj = cls.newInstance();
Method method = cls.getMethod(methodName);
method.invoke(obj);
//实现更改配置文件运行方法
}
}
Annotation注解
/**
*注解:
*概念:说明程序的.给计算机看的
*注释:用文字描述程序的.给程序员看的
*定义:注解(Annotation),也叫元数据.一种代码级别的说明.,它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次.它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释.
*作用分类:
编写文档:通过代码里标识的注解生成文档[生成文档doc文档]
命令行: javadoc AnnotationDamo.java,生成文档
javac MyAnno.java 编译
javap MyAnno.class 反编译
代码分析:通过代码里标识的注解对代码进行分析[使用反射]
编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查[overridel
*小结:
1,以后大多数时候,我们会使用注解,而不是自定义注解
2,注解给谁用?
1.编译器
2,给解析程序用
3,注解不是程序的一部分,可以理解为注解就是一个标签
*/
//注解格式
public @interface MyAnno {
/**
* JDK中预定义的一些注解
* *@Override:检测备注接的方法是否被继承自父类/接口
* *@Deprecate:表示该注解已过时
* *@SuppressWarnings:压制警告
* 一般传递All,了用于类与方法@SuppressWarnings("All")
*/
/**
* 自定义注解
*
* 通过编译(javac 名.java命令),在通过反编译(javap 名.class)
* 生成代码public interface MyAnno extends java.lang.annotation.Annotation{}
* 说明注解本质为接口,并继承Annotation
*
*/
/**
* 元注解:用来描述注解的注解
* *@Target:描述注解能够作用的位置,参数ElementType[]
* TYPE:可以作用于类上(只能)
* METHOD:可以作用于方法上
* FIELD:可以作用于成员变量上
* *@Retention:描述注解被保留的阶段
* *@Documented:描述注解是否被保留到api中
* *@Inherited:描述注解是否被子类继承
*
*/
//注解属性:抽象方法,
/**要求
* 返回值类型要求:基本数据类型,String,枚举,注解,以上类型数组
* 2.定义了属性,在使用时需要给属性赋值
* 1,如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值.
* 2.如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
*/
public abstract String show();
EnumDemo show2();//枚举
String name() default "张三";//默认值可以不用赋值
//如果方法名为value(仅有一个需要赋值),可以不用写(名称=值)
//数组赋值,使用大括号{}包裹,如果数组中只有一个值,可以省略(strs={"sss","ssaff"})或(strs="aaa")
}
数据库连接池与springJdbc
/** 数据库连接池
* 1,概念:其实就是一个容器(集合),存放数据库连接的容器.
* 当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器.
*2,好处:
* 1,节的资源
* 2,用户访问高效
*3,实现:
* 1,标准接口:Datasource javax.sq1包下的
* 1,方法:
* 获取连接:getConnection()
* 2,一般我们不去实现它,有数据库厂商来实现
* 1.C3P0:数据库连接池技术
* 2.Druid:数据库连接池实现技术,由阿里巴巴提供的
* /
/** c3p0数据库连接池
* 1.导入jar包(两个)c3p0-0.9.5.2.jar mchange-commons-java-.2.12.jar
* 2,定义配置文件:名称:c3po.properties或者c3po-config.xml
* (好像有其他方式[硬编码]不过不好)
* 路径:直接将文件放在src目录下即可.
* 3,创建核心对象数据库连接池对象ComboPooledDatasource
* 4.获取连接:getconnection
*
*/
<!--c3p0 xml配置-->
<c3p0-config>
<!--使用默认的配置读取连接池对象-->
<default-config>
<!--连接参数-->
<property name="drierClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/cmdc</property>
<property name="user">root</property>
<property name="password">1234</property>
<property name="initialPoolSize">5</property><!--初始化连接数量-->
<property name="maxPoolSize">10</property><!--最大连接数量-->
<property name="checkoutTimeout">3000</property><!--超时等待时间-->
</default-config>
<named-config name="otherc3p0">
<!--连接参数-->
<property name="drierClass">com.mysql.jabc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/cmdc</property>
<property name="user">root</property>
<property name="password">1234</property>
<property name="initialPoolSize">5</property>
<property name="maxPoolSize">8</property>
<property name="checkoutTimeout">1000</property>
</named-config>
</c3p0-config>
//c3p0调用
//获取连接池对象DataSource
DataSource ds = new ComboPooledDataSource();
//<named-config name="otherc3p0">里的配置内容
DataSource ds1 = new ComboPooledDataSource("otherc3p0");
/** Druid数据库连接池
* 1.导入jar包druid-1.0.9.jar
* 2.定义配置文件:
* 是properties形式的
* 可以叫任意名称,可以放在任意目录下
* 3.获取数据库连接池对象;
* 通过工厂来来获取DruidDatasourceFactory
* 4.获取连接:
*/
//properties配置文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/cmdc
username=root
password=1234
#初始化连接数量
initialSize=5
#最大连接数
maxActive=8
#超时等待时间
maxWait=3000
public static void main(String[] args) throws Exception {
//加载配置文件
Properties pro = new Properties();
InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
pro.load(is);
//获取连接池对象
DataSource ds = DruidDataSourceFactory.createDataSource(pro);
//获取连接
for (int i = 0; i < 11; i++) {
Connection conn = ds.getConnection();
System.out.println(i+" : "+conn);
if (i == 5) {
conn.close();//归还连接
}
}
}
package com.muyu.database.dataSource.druid;
import org.junit.Test;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* springJdbc
* JdbcTemplate
* 1,导入jar包
* 2,创建JdbcTemplate对象.依赖于数据源Datasource
* * JdbcTemplate template = new JdbcTemplate(ds);
* 3,调用JdbcTemplate的方法来完成CRUD的操作
* update():执行DML语句.增、删、改语句
* queryForMap():查询结果将结果集封装为map集合
* queryForlist():查询结果将结果集封装为list集合
* query():查询结果,将结果封装为JavaBean对象
* queryForobject:查询结果,将结果封装为对象
*/
/**
*update():执行DML语句.增、删、改语句
* queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value将这条记录封装为一个map集合
* 注意:这个方法查询的结果集长度只能是1
* queryForlist():查询结果将结果集封装为list集合
* 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
* query():查询结果,将结果封装为JavaBean对象query的参数:RowMapper
* 一般我们使用BeanPropertyRowMapper实现类.
* new BeanPropertyRowMapper<类型>(类型.class)
* 可以完成数据到JavaBean的自动封装
* queryForobject:查询结果,将结果封装为对象
* 一般用于聚合函数的查询
*/
public class JdbcTemplateDemo1 {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
private String sql = null;
/**
* 操作cmdc数据库中stu表完成以下
* 1,修改1号数据的score为100
* 2,添加一条记录
* 3,删除刚才添加的记录
* 4,查询id为1的记录,将其封装为Map集合
* 5,查询所有记录,将其封装为List
* 6.查询所有记录,将其封装为Stu对象的List集合
* 7.查询总记录数
*/
@Test
public void test1(){
//1,修改1号数据的score为100
sql = "update stu set score = 100 where id=?";
int count = template.update(sql, 1);
System.out.println(count);
}
@Test
public void test2(){
//2,添加一条记录
sql = "insert into stu values(?,?,?,?)";
int count = template.update(sql,null,"李留",24,57);
System.out.println(count);
}
@Test
public void test4(){
//4,查询id为1的记录,将其封装为Map集合
// sql = "select * from stu where id=?";//一个结果{id=1, name=战三, age=20, score=100}
// Map<String, Object> map = template.queryForMap(sql, 1);
sql = "select * from stu where age>? and age<?";//两条记录不可(长度只能为1)
Map<String, Object> map = template.queryForMap(sql, 10,20);
System.out.println(map);
}
@Test
public void test5(){
//5,查询所有记录,将其封装为List
sql = "select * from stu where age>? and age<?";//两条记录不可(长度只能为1)
List<Map<String, Object>> map_list = template.queryForList(sql, 10, 20);
System.out.println(map_list);
}
@Test
public void test6(){
//6.查询所有记录,将其封装为Stu对象的List集合
//自己实现RowMapper接口
sql = "select * from stu where id = ? or id = ?";
List<Stu> list = template.query(sql, new RowMapper<Stu>() {
@Override
public Stu mapRow(ResultSet rs, int rowNum) throws SQLException {
Stu stu = new Stu();
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
int score = rs.getInt("score");
stu.setId(id);
stu.setName(name);
stu.setAge(age);
stu.setScore(score);
return stu;
}
},1,2);
for (Stu s:list ) {
System.out.println(s);
}
}
@Test
public void test6_1(){
//6.查询所有记录,将其封装为Stu对象的List集合
/**
*test6的简化版,不自己定义接口RowMapper了
* 使用提供的实现类
*/
// sql = "select * from stu ";
sql = "select * from stu where name = ? and password = ?";
//如果数据有null,则会报错,因为null不能转成基本数据类型
//可以将可能出现null的数据类型由基本数据类型转为对应的封装类
//并重新生成一下set/get方法!!!!!
List<Stu> list = template.query(sql, new BeanPropertyRowMapper<Stu>(Stu.class),"刘华","123");
for (Stu stu : list) {
System.out.println(stu);
}
Stu stu = template.queryForObject(sql, new BeanPropertyRowMapper<Stu>(Stu.class), "刘华", "123");
System.out.println(stu);
}
@Test
public void test7(){
//7.查询总记录数
sql = "select count(id) from stu";
Long count = template.queryForObject(sql, Long.class);
System.out.println(count);
}
}
【day10_HTML】
javaScript
/**
* JavaScript = EcmaScript + JavaScript自己的(Bom+Dom)
*/
/*单目运算符 [+(-)正(负)号可将所有类型转为number类型
不能转为真值的('nan',undefined)为NAN
null,false转为0,turn,所有对象(object)为1]*/
var aaa ;
document.write(aaa+"<br/>");
document.write(+aaa+"<br/>");
/*方法调用参数列表个数不匹配可以执行,多的参数被隐藏内置对象(数组)(arguments)接收,且不能重载只能覆盖
Function 函数(方法)对象,length表示形参个数
//var fun = new Function(形参,"方法体")//不怎么样
Ffunction 名称(形参(不用写类型)){方法体}
var 名 = function(形参){};
*/
function add(a,b){
document.write(a+b+"<br/>");
}
function add(a,b,c){
document.write(a+b+c+"<br/>");
}
add(1, 2);//证明没有重载
add(1, 2,3);
add(1, 2,3,4);
//利用内置对象argument,实现任意个数和的sum方法
function sum() {//不用加参数
document.write("<hr/>");
var sum = 0;
for (var i = 0;i<arguments.length;i++) {
sum += arguments[i];
}
document.write(sum+"<br>");
}
sum(1, 2, 3);
sum(1, 2, 3, 4, 5);
/*Array数组对象
* 1.创建 var arr = new Array(元素列表) * var arr= new Array(默认长度)* var arr = [元素列表]
* 2.特点: 元素类型可变arr = [1,'sss',true],数组长度可变
* */
var arr = new Array(+5);
document.write(arr+"<br>");
var arr1 = [1,"sss",true];
arr1[10] = NaN;
document.write(arr1+' 长度 '+arr1.length+"<br>");
/**Date对象
*
*/
var date = new Date();
document.write("<hr>"+date+"<br>");
/**正则表达式对象
* var reg = new RegExp("正则表达式");
* var reg = /正则表达式/
**/
var reg = /^\\w{8,12}$/;
document.write("<hr>"+reg.test("aaa")+"<br>");
document.write(reg.test(undefined)+"<br>");//undefined竟然为true
/**全局变量Global
* 特点:全局对象,这个Global中封装的方法不需要对象就可以直接调用. 调用>>方法名()
* 方法:
* encodeURI():url编码
decodeURI():ur1解码
encodeURIComponent():ur1编码,编码的字符更多
decodeURIComponent():url解码
parseInt():将字符串转为数字
比+号更智能,
isNaN():判断是否为NaN的唯一方法,NaN==NaN也不能判断
eval("字符串"):将字符串用js解析并执行
*/
/**Bom
*概念:Browser object Model浏览器对象模型
* 将浏览器的各个组成部分封装成对象.
* 组成
* **window:窗口对象(包含 Dom[document]对象)
* *Window对象不需要创建可以直接使用window使用.window.方法名();
* window引用可以省略.方法名();
* 方法:
* 定时器:
* setTimeout()在指定的毫秒数后调用函数或计算表达式(执行一次).参数(js代码或者方法对象,毫秒值)
*, 返回值.唯一标识.用于取消定时器
* clearTineout()取消由setTimeout()方法设置的timeout.
* setInterval()按照指定的周期(以毫秒计)来调用函数或计算表达式.
* clearInterval()取消由setInterval()设置的timeout.
* Navigator:浏览器对象
* Screen:显示屏幕对象
* *History:历史记录对象
* 方法: back()加载history列表前一个URL
* forward() 加载列表下一个URL
* go() 加载列表中某个具体页面
* 属性:length 当前窗口的列表个数
* *Location:地址栏对象
* 方法: reload()重新加载当前文档.刷新
* 属性: href设置或返回完整的URL.
*/
/*DOm Document object Model 文档对象模型
HTML文档->dom树
dom树如下
文档
根元素:htmls
元素:<head> 元素:<body>
元索: <title> 属性-元素:<a> 元素:<h1>
文本: 文本: 文本:
文档标题 我的链接 标题
<html>
<head>
<title>文档标题</title>
</head>
<body>
<a>我的链接</a>
<h1>标题</h1>
</body>
</html>
*/
/*DOM
概念:Document object Model文档对象模型
*将标记语言文档的各个组成部分,封装为对象.可以使用这些对象,对标记语言文档进行CRUD的动态操作
*W3CDOM标准被分为3个不同的部分:
*核心DOM -针对任何结构化文档的标准模型
**Document:文档对象
**Element:元素对象
*Attribute:属性对象
Text:文本对象
Comment:注释对象
*Node:节点对象,其他五个的父对象
*XMLDOM -针对XML文档的标准模型[XMLDom创建于HTMLDom创建方式不一样]
*HTMLDOM -针对HTML文档的标准模型I
*/
/*核心Dom,方法属性看XMLDom文档
获取:Windows.document 或 document
方法:
获取Element对象
getElementById
创建其他Dom对象
createAttribute(name)
createComment()
createElement()
createTextNode()
5.DOM操作
1,内容操作
1.html():获取/设置元素的标签体内容<a><font>内容</font></a> -<a>.html-><font>内容</font>
html("设置内容")可加标签
2.text():获取/设置元素的标签体纯文本内容<a><font>内容</font></a> -<a>.text->内容
text("设置文本"):标签也会变成文本显示
3.val():获取/设置元素的value属性值
val("设置value值");
2.属性操作
1.通用属性操作
1. attr():获取/设置元素的属性
2. removeAttr():删除属性
3.prop():获取/设置元素的属性
4. removeProp():删除属性
* attr和prop区别?
1,如果操作的是元素的固有属性,则建议使用prop
2.如果操作的是元素自定义的属性,则建议使用attr
2.对class属性操作
1. addClass():添加class属性值
2. removeClass():删除class属性值
3. toggleClass():切换class属性,,如果存在(不存在)就删除(添加)一个类.
*toggleClass("one"):判断如果元素对象上存在class="one",则将属性值one删除掉.如果元素对象上不存在class="one",则添加
3.CRUD操作:
1. append():父元素将子元素追加到末尾
*对象1.append(对象2):将对象2添加到对象1元素内部,并且在未尾
2. prepend():父元素将子元素追加到开头
*对象1.prepend(对象2):将对象2添加到对象1元素内部,并且在开头
3. appendTo():
*对象1.appendTo(对象2):将对象1添加到对象2内部,并且在末尾
4. prependTo():[
*对象1.prependTo(对象2):将对象1添加到对象2内部,并且在开头
5. after():添加元素到元素后边
*对象1.after(对象2):将对象2添加到对象1后边.对象1和对象2是兄弟关系
6. before():添加元素到元素前边
*对象1.before(对象2):将对象2添加到对象1前边.对象1和对象2是兄弟关系
7. insertAfter()
*对象1.insertAfter(对象2公将对象2添加到对象1后边.对象1和对象2是兄弟关系
8. insertBefore()
*对象1.insertBefore(对象2):将对象2添加到对象1前边.对象1和对象2是兄弟关系
9. remove():移除元素
对象.remove():将对象删除掉
10. empty():清空元素的所有后代元素.
*对象,empty():将对象的后代元秦全部清空,但是保留当前对象以及其属性节点
*/
JQuery
//快速入门
/*JS对象与JQuery对象的区别
* 都可以当做数组使用,但是JQuery更加方便
* JQuery对象与js对象方法不通用
* 两者相互转换
* *jq --> js :jq对象[索引] 或者 jq对象.get(索引)
* *js --> jq :$(js对象)
* */
//选择器
/*1,分类
1.基本选择器
1.标签选择器(元素选择器)
*语法:$("html标签名")获得所有匹配标签名称的于元素
2.id选择器
*语法:$("#id的属性值")获得与指定id属性值匹配的元素
3.类选择器
*语法:$(".class的属性值")获得与指定的class属性值匹配的元素
3.并集选择器
*语法:$("选择器1,选择器2,...")包含多个选择器
2.层级选择器
1.后代选择器
*语法:$("A B")选择A元素内部的所有B元素
2.子选择器
*语法:$("A>B")选择A元素内部的所有B子元素
3.属性选择器
1,属性名称选择器
*语法:$("A[属性名]")包含指定属性的选择器
2.属性选择器
*语法:$("A[属性名='值']")包含指定属性等于指定值的选择器
3.复合属性选择器
*语法:$("A[属性名='值'][]...")包含多个属性条件的选择器
4.过滤选择器
1.首元素选择器
*语法::first获得选择的元素中的第一个元素
2,尾元素选择器
*语法::last获得选择的元素中的最后一个元素
3.非元素选择器
*语法::not(selecter)不包括指定内容的元素
4.偶数选择器
语法::even偶数,从0开始计数
5.奇数选择器
*语法::odd奇数,从0开始计数
6.等于索引选择器
*语法::eq(index)指定索引元素
7.大于索引选择器
*语法::gt(index)大于指定索引元素
8.小于索引选择器
*语法::lt(index)小于指定索引元素
9,标题选择器
*语法::header获得标题元素,固定写法
5.表单过滤选择器
1.可用元素选择器
*语法::enabled获得可用元素
2.不可用元素选择器
*语法::disabled获得不可用元素
3.选中选择器
*语法::checked获得单选/复选框选中的元素$("#id"::checked)
4,选中选择器
*语法::selected获得下拉框选中的元素*/
//jquery入口函数(dom文档加载文成好执行入口函数)
//相当于js中window.οnlοad=function(){},但是也有区别
// 区别:window.onload只能定义一次(只执行最后面的),而$(),可以多次
//jQuery高级
/** 1.动画
* 分析发现JQuery的显示和隐藏动画效果其实就是控制display(none)
1.三种方式显示和隐藏元素
1、默认显示和隐藏方式
1. show([speed, [easing],[fn]])
1.参数:
1.speed:动画的速度.三个预定义的值("slow","normal","fast")或表示动画时长的毫秒数值(如:1000)
2. easing:用来指定切换效果,默认是"swing",可用参数"linear"
*swing:动画执行时效果是先慢,中间快,最后又慢
* linear:动画执行时速度是匀速的
3.fn:在动画完成时执行的函数,每个元素执行一次.
2. hide([speed, [easing],[fn]])
3. toggle([speed],[easing],[fn])
2.滑动显示和隐藏方式
1. slideDown([speed], [easing],[fn])
2. slideUp([speed, [easing],[fn]])
3. slideToggle([speed], [easing],[fn])
3.淡入淡出显示和隐藏方式
1. fadeIn([speed], [easing],[fn])
2. fadeout([speed],[easing],[fn])
3. fadeToggle([speed, [easing],[fn]])
2.循环
1.js的遍历方式
*for(初始化值;循环结束条件;步长),可以使用break,continue
2.jq的遍历方式
1.jq对象.each(callback),callback:回调方法,不可使用break
可以在回调方法中return false充当break
可以在回调方法中return true充当continue
2.$.each(object,[callback])
object对象:就是要遍历的对象,但是可以是js对对象
3. for..of: 3.0之后版本才有
for(li of lis){
这里li是js对象,
}
3,事件绑定
1. jquery标准的绑定方式
jq对象.事件方法(回调函数);
*注:如果调用事件方法,不传递回调函数,则会触发浏览器默认行为.
*表单对象.submit();//让表单提交
2.on绑定事件/off解除绑定
jq对象.on("事件名称",回调函数)
jq对象.off("事件名称")//没有事件名,就会解绑所有的事件
3.事件切换:toggle
jq对象.toggle(fn1,fn2...) //1.9版本.toggle()方法删除,jQuery Migrate(迁移)插件可以恢复此功能.
当单击jq对象对应的组件后,会执行fn1.第二次点击会执行fn2
5.插件:增强JQuery的功能
1.实现方式:
1. $.fn.extend(object)
*增强通过Jquery获取的对象的功能$("#id"),即添加自定义方法
* //this:调用该方法的jq对象
2. $.extend(olject)
*增强JQeury对象自身的功能$/jQuery
* 即添加静态方法,直接$.方法(),调用
*/
/**
*
5.插件:增强JQuery的功能
1.实现方式:
1. $.fn.extend(object)*增强通过Jquery获取的对象的功能$("#id"),即添加自定义方法//this:调用该方法的jq对象
2. $.extend(olject)*增强JQeury对象自身的功能$/jQuery
*/
【day12_Bootstrap】
<!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">
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<!-- <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>-->
<!-- 只有当你的网页域名和要载入的静态文件存放的站点域名不一样的时候,使用这两个属性才有意义(并且因浏览器的规定 crossorigin 属性只有这个时候才能正常使用)-->
<script src="js/jquery-3.0.0.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="js/bootstrap.min.js"></script>
<style>
img{
width: 100%;
}
</style>
</head>
<body>
<!--
#响应式布局
*同一套页面可以兼容不同分辨率的设备.
*实现:依赖于栅格系统:将一行平均分成12个格子,可以指定元素占几个格子
*步骤:
1,定义容器.相当于之前的table,
容器分类:
1.container:两边留白
2.container-fluid:每一种设备都是100%宽度
2,定义行.相当于之前的tr. 样式:row
3,定义元素.指定该元素在不同的设备上,所占的格子数目.样式:col-设备代号-格子数目
设备代号:
1.xs:超小屏幕手机(<768px):co1-xs-12
2.sm:小屏幕平板(>=768px)
3.md:中等屏幕桌面显示器(>=992px)
4.lg:大屏幕 大桌面显示器(>=1200px)
注意:
1,一行中如果格子数目超过12,则超出部分自动换行.
2,栅格类属性可以**向上兼容**.栅格类适用于与屏幕宽度大于或等于分界点大小的设备.
3,如果真实设备宽度小于了设置栅格类属性的设备代码的最小值,会一个元素沾满一整行.
-->
</body>
</html>
【day14_XML相关】
##XML:
1,概念:Extensible Markup Language可扩展标记语言,
可扩展:标签都是自定义的.<user><cstudent>
2,功能
"存储数据
1,配置文件
2,在网络中传输
3.xm1与html的区别
1,xm1标签都是自定义的,html标签是预定义.
2.xml的语法严格,html语法松散I
3,xm1是存储数据的,html是展示数据
2.基本语法:
1.xml文档的后缀名.xml
2.xm1第一行必须定义为文档声明<?xml version="1.0"?>
3.xml文档中有且仅有一个根标签
4.属性值必须使用引号(单双都可)引起来
5,标签必须正确关闭
6.xml名称区别大小写
组成部分:1,文档声明
1,格式:<?xml属性列表 ?>
2、属性列表;
version:版本号
standalone:是否独立
encoding:编码方式
2,指令(了解);结合css的
<?xml-stylesheettype="text/css"href="a.css ?>
3,标签
4,属性
id唯一(需要约束)
5,文本
CDATA区:在该区域中的数据会被原样展示(不是CDATA区中特殊字符需要用HTML转义即:空格==> )
格式<![CDATA[数据]]>
<!-- "约束:规定xm1文档的书写规则
,作为框架的使用者(程序员):
1,能够在xm1中引入约東文档
2,能够简单的读们的束文档
*分类:
1,DTD:一种简单的约束技术
对于约束标签内容不能很好约束
2.Schema;一种复杂的约束技术-->
<!--dtd约束-->
<?xml version="1.0" encoding="GBK" ?>
<!--<!DOCTYPE students SYSTEM "student.dtd">-->
<!DOCTYPE students [
<!--<!ELEMENT>设置标签中小括号设置标签内标签-->
<!ELEMENT students (student+)>
<!--这里的(+)和正则表达式一个意义-->
<!ELEMENT student (name,age,sex)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!--<!ATTLIST 所在标签 属性名 ID(表示唯一) #REQUIRED(表示必须)>设置属性,-->
<!ATTLIST student number ID #REQUIRED>
]>
<!--
DTD:
"引入dtd文档到xml文档中
*内部dtd:将约束规则定义在xml文档中
<!DOCTYPE students [
内容
]>
*外部dtd:将约束的规则定义在外部的dtd文件中
*本地:<!DOCTYPE 根标签名 SYSTEM "dtd文件的位置">
*网络:<!DOCTYPE 根标签名 PUBLIC "dtd文件名字" "dtd文件的位置url")
-->
<students>
<student number="aa1">
<name>张三</name>
<age>23</age>
<sex>male</sex>
</student>
<student number="aa2">
<name>张三</name>
<age>23</age>
<sex>male</sex>
</student>
</students>
<!--schema约束-->
<?xml version="1.0" encoding="UTF-8" ?>
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cn/xml student.xsd
http://www.itcast.cn/xml2 student2.xsd"
xmlns="http://www.itcast.cn/xml"
xmlns:a="http://www.itcast.cn/xml2">
<student number="1234">
<name>aaa</name>
<age>15</age>
<sex>male</sex>
</student>
<a:user id="2_1234">
<a:name>asss</a:name>
<a:age>20</a:age>
<a:sex>male</a:sex>
</a:user>
</students>
<!--schema约束-->
<?xml version="1.0"?>
<xsd:schema xmlns="http://www.itcast.cn/xml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn/xml"
elementFormDefault="qualified">
<xsd:element name='students' type="studentsType"/>
<xsd:complexType name="studentsType">
<xsd:sequence>
<xsd:element name='student' type="studentType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="studentType">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType"/>
<xsd:element name="sex" type="sexType"/>
</xsd:sequence>
<xsd:attribute name="number" type="numberType" use="required"/>
</xsd:complexType>
<xsd:simpleType name="sexType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="male"/>
<xsd:enumeration value="female"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ageType">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="256"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="numberType">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
/**
* 解析:操作xml文档,将文档中的数据读取到内存中
* *操作xml文档
* 1,解析(读取):将文档中的数据读取到内存中
* 2、写入:将内存中的数据保存到xml文档中.持久化的存储
* *解析xml的方式:
* 1.DOM:将标记语言文档一次性加载进内存,在内存中形成一颗dom树
* *优点:操作方便,可以对文档进行CRUD的所有操作
* *缺点:占内存
* 2.SAX:逐行读取,基于事件驱动的.(存在指针)
* *优点:不占内存.
* *缺点:只能读取,不能增删改
* xml常见的解析器:
* 1.JAXP:sun公司提供的解析器,支持dom和sax两种思想
* 2.DOM4J:一款非常优秀的解析器
* 3.Jsoup:jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容.
* 它提供了一套非常省力的API,可通过DOM,css以及类似jQuery的操作方法来取出和操作数据.
* 4. puULL:Android操作系统内置的解析器,sax方式的.
*/
public class JsoupDemo1 {
/**
* *步骤;
* 1,导入jar包
* 2,获取Document对象
* 3、获取对应的标签Element对象
* 4,获取数据工
*/
@Test
public void demo1()throws IOException, URISyntaxException {
/**获取document对象方式
* 1.从一个URL,文件或字符串中解析HTML;根据xml文档
* 获取xml资源路径
* 2.使用DOM或CSS选择器来查找、取出数据江
* 3.可操作HTML元素、属性、文本;
*/
//如果路径有中文或空格,改成.toURI().getPath()
// .字节码文件.类加载器 .资源位置 .路径字符串
String path = JsoupDemo1.class.getClassLoader().getResource("student.xml").toURI().getPath();
System.out.println(path);
File file = new File(path);
System.out.println(file);
//InputStream is = DruidDemo1.class.getClassLoader().getResourceAsStream("druid.properties");
Document document = Jsoup.parse(file, "utf-8");
//获取对象 Elements相当于ArrayList
Elements elements = document.getElementsByTag("name");
System.out.println(elements.size());
for (Element element : elements) {
String name = element.text();
System.out.println(name);
}
}
/**
* 对象的使用:
* 1.Jsoup:工具类,可以解析html或xml文档,返回Document
* *parse:解析HTML或xml文档,返回Document
* parse(File file,String charsetName):解析文件
* parse(String html):解析xml或HTML字符串
* parse(URL url,int timeoutMillis):解析网络路径中xml或HTML文档
* 2.Document:文档对象.代表内存中的dom树
* 获取Element对象
* *不常用*getElementById(string id):根据id属性值获取唯一的element对象
* getElementsByTag(String tagName):根据标签名称获取元素对象集合
* getElementsByAttribute(string key):根据属性名称获取元素对象集合
* getElementsByAttributevalue(String key, string value):根据对应的属性名和属性值获取元素对象集合
* 3. Elements:元素Element对象的集合.可以当做Arraylist<Element>来使用
* 4.Element:元秦对象
* 1.获取Element对象:同上
* 2.获取属性值
* String attr(String key):根据属性名称获取属性值
* 3,获取文本内容
* String text():获取文本内容
* String html():获取标签体的所有内容(包括字标签的字符串内容)
* 5.Node:节点对象
* 是Document,Element的父类
*/
【day15_Tomcat】
Servlet体系
/**
* Servlet体系
* servlet接口 <--实现-- GenericServlet <--继承-- HttpServlet
*/
/**
* 1,当服务器接受到客户端浏览器的调求后,会解析调求URL路径,获取访问的 Servlet的资源路径
* 2.查找web,xm文件,是否有对应的< url-pattern>标签体内容.
* 3.如果有,则在找到对应的< servlet-c1ass>全类名
* 4.tomcat会捋字节码文件加载进内存,井且创建其对象
* 5.调用其方法
*
* Servlet的init方法,只执行一次,说明一个 Servlet在内存中只存在一个对象, Servlet是单例的
* 多个用户同时访间时,可能存在线程安全问题
* 解决:尽量不要在 Servlet中定义成员变量.即使定义了成员变量,也不要对修改值
*/
public class ServletDemo1 implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {System.out.println("init初始化方法,servlet创建时执行");}
@Override
public ServletConfig getServletConfig() {/*获取servlet配置对象*/return null;}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) {System.out.println("hello world");}
@Override
public String getServletInfo() {/*获取(版本,作者)等信息*/return null;}
@Override
public void destroy() {System.out.println("destroy被正常关闭执行,在servlet销毁之前调用");}
}
@WebServlet("/Gener")
public class GenericServletDemo extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse){System.out.println("GenericServletDemo");}
}
@WebServlet({"/Http","/Http1"})
public class HttpservletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp){System.out.println("HttpServlet");}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp){doGet(req,resp);}
}
request&response&context
/**
*## HTTP
*概念:Hyper Text Transfer protocol超文本传输协议 ,传输协议:定义了客户端和服务器端通信时,发送数据的格式
特点:
1,基于TCP/IP的高级协议
2,默认端口号:80
3,基于请求/响应模型的;一次请求对应一次响应
4,无状态的:每次请求之间相互独立,不能交互数据
历史版本;
"1.0:每一次请求响应都会建立新的连接
"1.1:复用连接
*/
/* 浏览器请求原理
1.tomcat服务器会根据请求url中的资源路径,创建对应的ServletDemo1的对象.
2.tomeat服务器,会创建request和response对象,request对象中封装请求消息数据.
3.tomcat将request和response两个对象传法递给service方法,并且调用service方法
4,程序员(我们),可以通过request对象获取请求消息数据,通过通过response对象设置响应消息数据
5.服务器在给浏览器做出响应之前,会从response对象中拿程序员设置的响应消息数据.
*/
消息格式
/* *请求消息数据格式
* 1.请求行
* 请求方式请求u1请求协议/版本
* 例:Get /login. html Http/1.1
* 2.请求头
* 请求头名称:请求头值
* *常见的请求头
* 1.User- Agent:浏览器告诉服务器,我访问你使用的浏览器版本信息
* 可以在服务器端获取该头的信息,解决浏览器的兼容性问题
* 2:Refererhttp://localhost/login.html
* *告诉服务器,我(当前请求)从哪里来?
* *作用
* 1.防盗链
* 2.统计工作:
* 3.请求空行
* 分隔请求数据
* 4.请求体
* *封装P0ST请求消息的请求参数的
*
*
* 例:
* 请求行:
* POST /day15/demo1/hello HTTP/1.1
* 请求头:
* Host: localhost
* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0
* Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,* /*;q=0.8
* Accept-Language:zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
* Accept-Encoding:gzip,deflate
* Content-Type:application/x-www-form-urlencoded
* Content-Length:14
* Origin:http://localhost
* Connection:keep-alive
* Referer:http://localhost/day15/
* Cookie:JSESSIONID=8
* [空行]
* 请求体:
*
*
* 响应消息:服务器发送给客户端的数据
* 数据格式
* 响应行 HTTP/1.1 304
* 组成: 协议/版本 状态码 状态码描述
* 状态码:服务器告诉浏览器本次请求状态(三位数字)
* 分类
* 1.1xx服务器接收客户端消息,但不接收成功,等一段时间后,发送1XX码,询问是否继续发消息
* 2.2xx:成功
* 3.3xx:重定向。302(重定向) 304(访问缓存)[当第二次访问后,服务器发现浏览器本地有,便会发送304,告知浏览器]
* 4.4xx:客户端错误。404(请求路径不存在)405(请求方式没有doXXX()方法)
* 5.5xx:服务端错误。500(服务器内部议程)
* 响应头 格式 [头名称: 值]
* 常见响应头:
* 1.Content-Type: 服务器告诉客户端本次请求体数据格式及编码格式
* 2.Content-disposition:告诉客户端以什么格式打开相应数据
* 值:in-line:默认值,在当前页面内打开
* attachment;filename=xxx:以附件形式打开响应体.(文件下载)
* 响应空行
* 响应体:就是真是的传输数据
*
* 响应字符串格式
* HTTP/1.1 304(响应行)
* Content-Type: text/html;charset=utf-8(响应头)
* Content-Language: zh-CN
* Content-Length: 648 [字节个数]
* Date: Mon, 23 Aug 2021 06:58:19 GMT [日期]
* Keep-Alive: timeout=20
* Connection: keep-alive
* (空行)
* <!DOCTYPE html>(响应体)
* <html lang="en">
* <head>
* <meta charset="UTF-8">
* <title>Hello Response</title>
* </head>
* <body>
* Hello Response
* </body>
* </html>
*
* ServletContext对象:代表整个web应用,可以和程序的容器(服务器)
*/
request对象
/**
* Request
* 1. request对象和 response对象的原理
* 1. request和 response对象是由服务器创建的.我们来使用它们
* 2. request对象是来获取请求消息, response对象是来设置响应消息
* 2. request对象继承体系结构:
* ServletRequest 接口
* | 继承
* Httpservletrequest--接口
* | 实现
* org. apache. catalina connector. RequestFacade 类( tomcat编写)
* request:功能
* 获取请求数据
* 获取请求行:
* 例 请求行:GET /day15/demo2/Request?name=%E4%BD%A0%E5%A5%BD HTTP/1.1
* 请求方式[getMethod() GET]
* 虚拟目录[getContextPath() /day15]
* Servlet路径[getServletPath() /demo2/Request]
* 获取Get方法请求参数[getQueryString()]
* 获取请求URI(统一资源标识符(大)):[getRequestURI() /day15/demo2/Request]
* URL(同一资源定位符(小))[StringBuffer getRequestURL() http://localhost/day15/demo2/Reques]
* 协议版本[getProtocol()]
* 客户机IP地址[getRemoteAddr()]
* 获取请求头
* getHeader(String):根据请求头名称获取请求值
* Enumeration<String> getHeaderNames():获取所有请求头数据
* 获取请求体post
* 步骤:1.获取流对象(字符输入流[文字,表单],字节输入流[文件,图片])
* BufferedReader getReader():获取字符输入流,只能操作字符数据
* 见注册regist页面
* ServletInputStream getInputStream():获取字节输入流,可以操作所有类型数据,可以也操作字符
* 在文件上传演示
* 2.再拿数据
* 其他功能
* 1.获取请求参数(通用方式)
* 1.String getParameter(String name):根据名称获取值
* 2.String[] getParameterValues(String name):根据参数名称获取参数值数组
* 3.Enumeration<String> getParameterNames():获取所有请求参数名称
* 4.map<String,String[]> getParameterMap():获取所有参数及其值得map集合
* 2.请求转发:一种在服务器内部跳转的方式
* 1.通过request对象获取转发器对象:RequestDispatcher getRequestDispatcher(String path)
* 2.使用RequestDispatcher对象进行转发: forward(ServletRequest,ServletResponse)
* 特点:1.资源路径(浏览器地址栏)不发生变化
* 2.只能访问当前服务器内部部的资源
* 3.转发是一次请求(多次转发是一个请求)
* 3.共享数据
* 域对象:一个有作用范围对象,可以在方位内共享数据
* request:一次请求范围
* 方法
* 1. void setAttribute( string name, object obj):存储数据
* 2. Object getAttitude( String name):通过键获取值
* 3, void removeAttribute( string name):通过键移除键值对
* request.getParameter()方法传递的数据,会从Web客户端传到Web服务器端,代表HTTP请求数据。request.getParameter()方法返回String类型的数据。
* request.setAttribute()和getAttribute()方法传递的数据只会存在于Web容器内部,在具有转发关系的Web组件之间共享。这两个方法能够设置Object类型的共享数据。
* [[[getParameter得到的都是String类型的。或者是http://a.jsp id=123中的123,或者是某个表单提交过去的数据。
* getAttribute则可以是对象。
* getParameter()是获取POST/GET传递的参数值;
* getAttribute()是获取对象容器中的数据值;
* getParameter:用于客户端重定向时,即点击了链接或提交按扭时传值用,即用于在用表单或url重定向传值时接收数据用。
* getAttribute:用于服务器端重定向时,即在sevlet中使用了forward函数,或struts中使用了mapping.findForward。getAttribute只能收到程序用setAttribute传过来的值。
* 另外,可以用setAttribute,getAttribute发送接收对象.而getParameter显然只能传字符串。]]]
* * 4.获取servletContext
* getServletContext()
* 5.动态获取虚拟目录
* request.getContextPath();
*/
Response对象
/**
* Response对象
* 功能:设置相应消息
* 设置相应行HTTP/1.1 200 ok:设置状态码:setStatus(int sc)
* 设置响应头:setHeader(String name,String value),,setContentType("text/html;charset=gbk")设置数据格式及编码格式
* 设置响应体:
* 步骤1.获取输出流
* 字符输出流:输出字符数据:PrintWriter getWriter()(只能输出字符)
* 字节输出流:输出字节数据:ServletOutputStream getOutputStream()(可以输出任意)
* 2.使用输出流,将数据输出到客户端浏览器
*
* 案例
* 完成重定向:重定向是由A资源通过响应头告诉浏览器B资源(要跳转的资源)的路径,并且告知浏览器302状态码
* 代码实现, resp.setStatus(302);resp.setHeader("location","../demo1/hello");
* resp.sendRedirect("资源地址");
* 重定向特点(与转发完全相反)
* 地址栏发生改变
* 可以访问其他站点(服务器)资源
* 重定向是两次请求(通过浏览器抓包来看)
* 路径写法(./与不写一样)(以/开头为绝对路径)
* [判断给谁用?从哪发出]
* (转发是服务器内部相互调用资源,所以是给服务器使用)
* (重定向(A标签,from表单也是)是服务器告知浏览器转发路径,所以是给浏览器使用)
* 给客户端浏览器使用:需要加虚拟目录(项目访问路径)
* 给服务器使用:不需要加虚拟目录
* (为什么:因为给服务器使用的,是在特定服务器内部,一个服务器里没有重名的路径,所以不需要,
* 但是给浏览器使用可能存在多个服务器出现相同名称路径而不知道是谁)(自己理解)
*
*
*/
ServletContext对象
/**ServletContextDemo对象:代表整个web应用,可以和程序的容器(服务器)来通信
* 获取:1.通过request获取,request.getServletContext()
* 2.通过HttpServlet获取,this.getServletContext()
* 通过哪种方式都是一个
* 功能:1.获取MIME类型 :在互联网通信过程中定义分一种数据类型
* 格式: 大类型/小类型 text/html image/jpeg
* 获取:String getMimeType(String file)
*
* 2.域对象:共享数据,它的范围为所有用户,可以不再一个浏览器,例:去context包
* 使用谨慎,使用过多可导致压力过大
* 3.获取文件真实(服务器)路径
* web项目会放在两处(tomcat服务器(浏览器访问tomcat里的),本地工作空间)
*
*/
@WebServlet("/ServletContextDemo")
public class ServletContextDemo extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取Mime类型
ServletContext context = this.getServletContext();
String fileName = "a.jpg";
String mimeType = context.getMimeType(fileName);
System.out.println(mimeType);
//web目录下的资源
String b_txt = context.getRealPath("/b.txt");
System.out.println(b_txt);
//WEB-INF下的资源
String c_txt = context.getRealPath("/WEB-INF/c.txt");
System.out.println(c_txt);
//src下的资源,会保存到WEB-INF下的classes里面
// src下的资源也可以使用getClass().getClassLoader()访问,但是这种方式不能访问web的内容;
String a_txt = context.getRealPath("/WEB-INF/classes/a.txt");
System.out.println(a_txt);
}
}
cookie客户端会话技术
/**会话技术
* 会话:一次会话中包含多个请求和相应
* 一次会话:浏览器第一次给服务器请求,会话建立,直到一方断开为止(http通讯请求之间相互独立,会话技术就是让请求间有交互)
* 功能:客户端会话技术:cookie
* 服务器会话技术:session
*/
/**Cookie:客户端会话技术,将数据保存到客户端
* 步骤:创建cookie对象new Cookie(String name,String value)
* 发送Cookie对象 response.addCookie(Cookie c)
* (发送了cookie,浏览器在每次请求中都会带有cookie请求头,携带cookie数据)
* 接受Cookie Cookie[] request.getCookie()
* 原理***基于响应头(set-cookie(可多个))与请求头(cookie(一个数据用;分隔))实现的
* _____________ _____________
* [ ] 请求cookie [ ]
* [ 客户端浏览器 ] 设置响应头(set-cookie:name=value) [ 服务器 ]
* [ ] 第2次请求,设置请求头(cookie:name=value) [ ]
* [_____________] 响应 [_____________]
* 细节:
* 一次可发送多个cookie,响应头(set-cookie(可多个))与请求头(cookie(一个数据用;分隔))
* cookie在浏览器保存多长时间
* 模式情况下,当浏览器关闭后,cookie数据别销毁
* 设置Cookie声明周期,使其持久化存储
* setMaxAge(int seconds)
* 1.正数:将cookie数据写到硬盘的文件中.seconds=30==>30秒后自动删除
* 2.负数:默认值
* 3.零:不代表他存在内存,也不代表他存在硬盘,而是代表删除cookie信息
* cookie存中文(可支持中文,但不支持空格等特殊字符)
* 在tomcat8之前不能直接存中文(报错)
* 需要将中文数据转码--一般采用URL编码(%E3)
* 在tomcat8之后可以
* cookie共享问题
* 假设在一个tomcat部署多个web项目,
* 默认情况下不能共享数据
* setPath(String path):设置cookie的获取范围,
* 默认为当前虚拟目录setPath("/day15"),可以设置setPath("/")设置为服务器内
* 不同服务器共享cookie问题(使用域名的特性)
* news(二级域名).[baidu.com](一级域名)
* setDomain(String path):如果设置以及域名相同,name多个服务器之间cookie可以共享
* *setDomain(".baidu.com"),那么tieba.baidu.com与news.baidu.com之间cookie可以共享
* cookie的特点和作用
* 1.cookie储存数据在客户端浏览器(安全性低,易丢失)
* 2.浏览器对单个cookie大小有限制(4K),雨季同一个域名下的总cookie数量也有限制(持久化的)(20)
*
* 作用:
* 1.cookie一般存储少量不太敏感的数据
* 2.在不登录的情况下,完成服务器对客户用户的身份识别(保存设置)
*/
@WebServlet("/cookieDemo1")
public class Cookie_SessionDemo extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建cookie对象
Cookie cookie = new Cookie("ffff", "aaaaa");
Cookie cookie1 = new Cookie("name", "zhangsan");
Cookie cookie2 = new Cookie("aaa", "hehe");
//1.1设置cookie存活时间
cookie.setMaxAge(60);
//设置在当前服务器共享cookie信息
cookie.setPath("/");
// cookie1.setMaxAge(-1);
// cookie2.setMaxAge(-1);//这个设置-1在下面好像就全为-1了
//提示警告:由于 Cookie “msg”的“SameSite”属性设置为“None”,但缺少“Secure”属性,此 Cookie 未来将被拒绝。
//2.发送Cookie
response.addCookie(cookie);
// response.addCookie(cookie1);
// response.addCookie(cookie2);
}
}
cookie采用URL编解码存储特殊字符案例(这里空格是特殊字符)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {
response.setContentType("text/html;charset=utf-8");
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年mm月dd日 hh:mm:ss");
String str_date = sdf.format(date);
//特殊字符需要编码然后存到cookie里,读取时也要解码
System.out.println("编码前的数据: "+str_date);
str_date = URLEncoder.encode(str_date, "utf-8");
System.out.println("编码后的数据: "+str_date);
Cookie[] cookies = request.getCookies();
boolean tai = true;
if (cookies != null && cookies.length > 0) {
for (Cookie cookie : cookies) {
String name = cookie.getName();
System.out.println(name);
if ("lastTime".equals(name)) {
String value = cookie.getValue();
System.out.println("解码前的数据: "+value);
value = URLDecoder.decode(value, "utf-8");
System.out.println("解码后的数据: "+value);
try {
response.getWriter().write("<h1>欢迎回来,你上次的访问时间为:" + value+"</h1>");
} catch (IOException e) {
e.printStackTrace();
}
cookie.setValue(str_date);
tai = false;
cookie.setMaxAge(60*60*24*3);
response.addCookie(cookie);
break;
}
}
}
if (cookies == null || cookies.length == 0||tai) {
try {
response.getWriter().write("<h1>欢迎您首次访问页面:</h1>");
} catch (IOException e) {
e.printStackTrace();
}
Cookie c = new Cookie("lastTime", str_date);
c.setMaxAge(60*60*24*3);
response.addCookie(c);
}
}
/*怎么证明jsp是servlet
找运行tomcat后的CATALINA_BASE后的目录,然后往下便可找到jsp文件夹里的jsp.java的源代码,jsp运行时也就是执行的这个class文件(\work\Catalina\localhost\day15\org\apache\jsp)
*/
session服务器会话技术
/**session:服务器会话技术
* 获取:request.getSession(),方法getAttribute(),setAttribute(),removeAttribute()
* 原理:
* 服务器如何确保一次会话范围内,多次获取的session的对象是同一个:
* 依赖于cookie,当浏览器第一次获取session时,没有cookie(JSESSIONID),
* 则会在浏览器创建一个session对象,并获取id,并在cookie中存储(JSESSIONID=7s8ds454)
* 当再次访问时获取cookie中id值并找到服务器内存中的session对象进行操作
* //我在B站弹幕发送:session本质确实是cookie, 但是也就在cookie中存入的session对象的id,不是数据,安全的,除非服务器被黑了
* //原来以为错了,但是想想应该没错,session就应该是在服务器中创建的,但为什么每个浏览器执行时,都有不一样的session对象,知道是多个会话,还是不懂原理.
* 细节:1.等客户端关了不是一个session对象
* 默认不是可以自己手动创建cookie(服务器关了好像就没了)
* Cookie c = new Cookie("JSESSIONID",session.getId());
* c.setMaxAge(60*60);//一小时
* response.addCookie(c);
* 2.客户端不关闭,服务器关闭也是一个session对象
* 为了让客户体验更佳,可以使session不是同一个,但保证数据不丢失
* (如果长时间不操作,服务器自动关闭,数据丢失,可能会影响用户体验)
* (tomcat已经自动帮我们做了)
* (找到项目[E:\文档\大学之道\大三方向课\再来一遍\day15tomcat\out\artifacts])
* 将项目导成war包(好像不能有图片(或者视频),把img文件删了)
* 将war包复制到本地tomcat,Webapps文件夹中,(D:\Program Files\Apache Software Foundation\Tomcat 9.0.45\webapps)
* 打开服务器自动部署,访问session(这个cookieDemo1)正常关闭服务器(shutdown.bat),
* 会自动序列化(钝化)项目中session对象(SESSIONS.ser)到work文件中(D:\Program Files\Apache Software Foundation\Tomcat 9.0.45\work)
* 再次启动服务器会自动读取(SESSIONS.ser)并将其删除(活化),访问session发现仍存在(JSESSIONID一样,地址id可能不一样)
* *****idea只能做到钝化,并不能做到活化
* session的钝化
* 当服务器正常关闭之前,将session对象序列化到硬盘上
* session的活化
* 在服务器启动后,将session文件转化到内存中的session对象即可
* idea只能实现钝化,活化的过程不能实现,因为idea打开服务器是会自动删除work目录,更不用说SESSIONS.ser文件了
* 3.session什么时候被销毁?
* 1.服务被关闭
* 2.session对象调用invalidate();
* 3.session默认失效时间tomcat->conf
* ->web.xml(所有项目的父配置文件)[也可以找相应项目的web.xml设置]->session-config
* <session-config>
* <session-timeout>30</session-timeout>
* </session-config>
* 特点:储存一次会话多次请求,存在服务器端,可以任意类型,任意大小
*/
EL表达式与JSTL
<!-- jsp知识点-->
<%--out.print()在哪定义在哪输出
response.getWriter().writer() 会在out之前输出
因为他俩都有相应的缓冲区,而服务器每次先找的都是response缓冲区--%>
<%--1.指令
*作用:用于配置JSP页面,导入资源文件
*格式:
<%@指令名称属性名1=属性值1属性名2=属性值2...%>
*分类:
1. page:配置JSP页面的
contentType:等同于response.setcontentType()
1,设置响应体的mime类型以及字符集
2,设置当前jsp页面的编码(只能是高级的IDE才能生效,如果使用低级工具,则需要设置pageEncoding属性设置当前页面的字符集)
* import:导包
* errorPage:当前页面发生异常后,会自动跳转到指定的错误页面
* isErrorPage:标识当前也是是否是错误页面.
*true:是,可以使用内置对象exception
* false:否.默认值.不可以使用内置对象exception
*isELIgnored="true"不使用el表达式
2. include:页面包含的.导入页面的资源文件
* <%@include file="top.jsp*"%>:导入资源
3. taglib
* <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"
prefix:前缀,自定义的%>
2.注释:
1.html注释:
<!---->:只能注释html代码片段
2.jsp注释:推荐使用
<%-%>:可以注释所有
3.内置对象
*在jsp页面中不需要创建,直接使用的对象
-共有9个:
变量名真实类型作用
bageContext PageContext当前页面共享数据,还可以获取其他八个内置对象
Irequest HttpServletRequest-次请求访问的多个资源(转发)
session HttpSession一次会话的多个请求间
application Servletcontext所有用户间共享数据
responseHttp ServletResponse响应对象
page Object当前页面(Servlet)的对象this
out JspWriter输出对象,数据输出到页面上
config ServletconfigServlet的配置对象
exception Throwable异常对象
--%>
<!-- EL表达式知识点-->
<%--
1.运算:
*运算符:
1,算数运算符:+- * /(div) %(mod)
2.比较运算符:><>=<===!=
3.逻辑运算符:&&(and)||(or)!(not)
4.空运算符:empty
*功能:用于判断字符串、集合、数组对象是否为null并且长度是否为0
* ${empty list}
2.获取值
1.el表达式只能从域对象中获取值
2,语法:
1.${域名称.键名}:从指定域中获取指定键的值
域名称:
1. pagescope一>pageContext
2. requestscope->request
3. sessionScope-> session
4. applicationscope 一> application (Servletcontext)
*举例:在reqyest域中存储了name=张三
*获取:${reqdestscope.name}
2.${键名}:表示依次从最小的域中查找是否有该键对应的值,直到找到为止.${name}
--%>
<!-- JSTL知识点-->
<%--
##JSTL
1.概念:JavaServer Pages Tag LibraryJSP标准标签库
*是由Apache组织提供的开源的免费的jsp标签<标签>
2.作用:用于简化和替换jsp页面上的java代码
3.使用步骤:
1,导入jstl相关jar包
2.引入标签库:taglib指令:<%@ taglib%>
3.使用标签
4,常用的JSTL标签
1.if:相当于java代码的if语句
c:if标签<c:if test="true">
1.属性:
*test必须属性,接受boolean表达式*如果表达式为true,则显示if标签体内容,如果为false,则不显示标签体内容
2. choose:相当于java代码的switch语句
<c:choose> <c:when test="true">值</c:when><c:otherwise>数字输入有误</c:otherwise> </c:choose>
3.foreach:相当于java代码的for语句
1.完成重复的操作
for(inti=0;i<10;i++){
*属性:
begin:开始值
end:结束值
var:临时变量
step:步长
varStatus:循环状态对象
index:容器中元素的索引从0开始
count:循环次数从1开始
2.遍历容器
List<User> list;
for(User user :list){
*属性:
items:容器对象
var:容器中元素的临时变量
varStatus:循环状态对象
index:容器中元素的索引从0开始
count:循环次数从1开始
--%>
filter过滤器
/**
* Filter:过滤器:当访问服务器资源是,过滤器可以拦截,完成一些特殊功能
* 一般用于完成通用的操作.如:登陆验证(有些资源必须在登陆是才能访问),统一编码处理(request等更改编码),敏感字符过滤
* 细节: web.xml配置
* 过滤器执行流程
* 过滤器生命周期
* 过滤器配置详情
* 拦截路径配置
* 拦截集体资源: /index.jsp
* 拦截目录: /user/* 访问/user下资源执行
* 后缀名拦截: *.jsp 访问jsp后缀执行(不用/)
* 拦截所有: /*
* 拦截方式配置:(可以服务器内部访问资源不经过浏览器(转发跳转))
* 注解配置dispatchTypes属性(可以多个值一起)
* 1.request:默认值.浏览器直接请求资源
* 2.forward:只用转发访问资源时,才执行
* 3.include:包含访问资源
* 4.error:错误跳转资源
* 5.async:异步访问资源
* web.xml配置<dispatcher></dispatcher>标签即可
* 过滤器链(配置多个过滤器)
* 执行顺序,如果有两个过滤器则为:过滤1(放)->过滤2(放)->回来->过滤器2(放)->过滤1
* 先后问题:注解配置:按类名的字符串顺序比较,值小的先执行,(不是ACSII码表(不区分大小写),可以先认为把小写当成大写比较)(数字->字母(大小写一样)->下划线)
* web.xml配置:谁<filter>配置在前谁先
* 两种方式都有,则先执行web.xml中的
*/
//@WebFilter(value ="/demo1/hello",dispatcherTypes = DispatcherType.FORWARD)
@WebFilter(value ="/*",dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST})
public class FilterDemo1 implements Filter {
/**
* 每一次请求资源被拦截时,会执行
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("FilterDemo执行");
//如果不执行就不会看到资源
System.out.println("FilterDemo111放行了");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("FilterDemo111放行完成");
}
/**
* 在服务器启动后,会创建Filter对象,然后调用init方法,只执行一次
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
ry {
//获取真实路径
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
//读取文件
//BufferedReader流创建出来,默认问gbk的编码(本地都默认为gbk)
BufferedReader br = new BufferedReader(new FileReader(realPath));
//每一行添加list中
String line = null;
while ((line = br.readLine()) != null) {
list.add(line);
}
br.close();
// System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 在服务器关闭后,filter对象销毁,如果服务器正常关闭,则会执行destroy方法,只一次
*/
@Override
public void destroy() {
}
}
/*xml配置
<filter>
<filter-name>demo2</filter-name>
<!-- 拦截路径-->
<filter-class>com.filter.FilterDemo2</filter-class>
</filter>
<filter-mapping>
<filter-name>demo2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
*/
listenter监听器
/**
* Listener:监听器
* *概念:web的三大组件之一.
* *事件监听机制
* *事件:一件事情
* *事件源:事件发生的地方
* *监听器:一个对象
* *注册监听:将事件、事件源、监听器绑定在一起.当事件源上发生某个事件后,执行监听器代码
* *ServletContextListener(其中一类监听器):监听servletContext对象的创建和销毁
* *方法;
* * void contextDestroyed(ServletContextEvent sce):ServletContext对象被销毁之前会调用该方法
* 相当于tomcat中init ,可以用于加载资源,并通过<context-param>配置路径
* <context-param>
* <param-name>contextConfigLocation</param-name>
* <param-value>WEB-INF/classes/applicationContext.xml</param-value>
* </context-param>
* * void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法
* 相当于servlet中destroy
* *步骤
* 1,定义一个类,实现servletcontextlistener接口
* 2.复写方法
* 3.配置
* 1.web.xml 只需要配置<listener><listener-class></listener-class></listener>
* 2.注解只需配置 @WebListener()
*/
//@WebListener()
public class ContextLoaderListener implements ServletContextListener{
/**
* 监听ServletContext对象创建的,ServletContext对象服务器启动后自行创建,
* 在服务器启动后自动调用
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
//加载资源文件
//1.获取ServletContext对象
ServletContext servletContext = sce.getServletContext();
//2.加载资源文件
String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
//3.获取真实路径
String realPath = servletContext.getRealPath(contextConfigLocation);
//4.加载进内存
try {
FileInputStream fis = new FileInputStream(realPath);
System.out.println(fis);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("ServletContext对象被创建...");
}
/**
* 在服务器关闭后,ServletContext对象被销毁,当服务器正常关闭后该方法被调用
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象被销毁");
}
}
/** xml配置
<listener>
<listener-class>com.listener.ContextLoaderListener</listener-class>
</listener>
*/
/** xml配置自定义src中配置文件路径
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
*/
代理模式
【day18_Ajxa&json】
ajxa
原生js实现ajxa
/*
* #AJAX:
1.概念:ASynchronous Javascript And XML异步的Javascript和XML
1,异步和同步:客户端和服务器端相互通信的基础上
*客户端必须等待服务器端的响应.在等待的期间客户端不能做其他操作.
客户端不需要等待服务器端的响应.在服务器处理请求的过程中,客户端可以进行其他的操作.
Ajax是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术.
通过在后台与服务器进行少量数据交换,Ajax可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.
传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面.
提升用户的体验
2.实现方式:
1.原生的JS实现方式
2.JQeury实现方式
1. $.ajax()
2. $.get()
3.$.post()*/
function fun() {
//1.创建核心对象
var xmlhttp;
if (window.XMLHttpRequest) {//高版本
xmlhttp = new XMLHttpRequest();
} else {//IE6,IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//2.发送请求
/*参数,
1,请求方式.GET、POST
get方式:请求参数在URL后拼接,send方法为空参
post方式:请求参数在send方法中定义send("username=tom")
2,请求的URL:
3.同步或异步请求.true《异步)或false(同步)*/
xmlhttp.open("GET", "ajaxServlet?username=tom", true);
//3.发送请求
xmlhttp.send();
//4.接受并处理来自服务器中数据
//4.接受并处理来自服务器的响应结果
//获取方式:xmlhttp.responseText
//什么时候获取?当服务器响应成功后再获取
//当xmlhttp对象的就绪状态改变时,触发事件onreadystatechange.
xmlhttp.onreadystatechange=function() {
//判断readyState就绪状态是否为4,判断status响应状态码是否为200
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
//获取服务器的响应结果
var responseText = xmlhttp.responseText;
alert(responseText);
}
}
}
JQery实现ajxa
/*
JQeury实现方式
1. $.ajax()
$.ajax({键值对})
2. $.get()//get请求 更简单
路径,参数 ,函数 ,类型
$.get(url,[data],[callback],[type])
3.$.post()//更简单 */
function fun() {
/*$.ajax({
url: "ajaxServlet",//请求路径
type: "post",//请求方式
// data: "username=tom&age=20",//请求数据
data:{"username":"tom", "age": 123},//json请求数据
success:function (data) {
alert(data);
},//响应成功的回调方法
error:function () {
},//出现错误调用此方法
dataType:"text"//设置接受响应格式
})*/
//$("#registerForm").serialize()序列化表单里数据 ?username=xxx&password=xxx...
/*$.get("ajaxServlet", {username: $("#registerForm").serialize(), age: 20}, function (data) {
alert(data);
}, "text");*/
$.post("ajaxServlet", {username: "rose", age: 20}, function (data) {
alert(data);
}, "text");
json
/*#JSON:
1.概念:JavaScript object NotationJavascript对象表示法
Person p = new Person(); p.setName("张三");
json就是把js变成对象方便实用
var p ={"name":"张三","age":23,"gender":"男"};
*json现在多用于存储和交换文本信息的语法
*进行数据的传输
JSON 比XML更小、更快,更易解析.
2,语法:
1.基本规则
数据在名称/值对中:json数据是由键值对构成的
*键用引号(单双都行)引起来,也可以不使用引号
*值得取值类型:
1.数字(整数或浮点数)
2,字符串(在双引号中)
3,逻辑值(true或false)
4、数组(在方括号中){"persons":[{},{}]}
5.对象(在花括号中){"address":{"province":"陕西".}}
6. null
*数据由逗号分隔:多个键值对由逗号分隔
*花括号保存对象:使用{}定义json格式
方括号保存数组:[]
2,获取数据
1.json对象.键名 //不需要加引号
2.json对象["键名"] //需要加引号
3、数组对象[索引]
//json数据循环遍历*/
var person = {"name": "张三", "age": 23, "gender": true};
var ps = [{"name": "张三", "age": 23, "gender": true},
{"name": "李四", "age": 24, "gender": true},
{"name": "王五", "age": 25, "gender": true}];
for (var key in person) {
//这样获取不到值,
// 相当于获取数据的第一种方法,但key带有引号(相当于person."name")获取不到
//需要采用第二种方式
// alert(key + " : " + person.key);
// alert(key + " : " + person[key]);
}
/*
java与json的数据转化(json可以转成任意语言的对象)
*转换需要解析器
常见解析器:JsonLib,Gson(google),fastJson(阿里),Jackson(springMVC框架中内置解析器)
1.java转json对象:(常用)(jackson)
步骤:1.导入Jackson相关jar包
2.创建Jackson核心对象ObjectMapper
3.调用objectMapper的相关方法(例:见JacksonTest.test1)
1.json转java对象:
步骤:1.导入Jackson相关jar包
2.创建Jackson核心对象ObjectMapper
3.调用objectMapper的相关方法(例:见JacksonTest.test5)
1.readValue()
注解
1.@JsonIgnore: 排除属性, 转成字符串时就不会有该属性
2.@JsonFormat:属性格式化
复杂java对象转换 list->json map->json
*/
【day19_redis 非对称数据库】
/** jedis.properties配置
host=127.0.0.1
port=6379
maxTotal=50
maxIdle=10
* /
/**
* Jedis操作各种redis中的数据结构
* 1)字符串类型string
* set
* get
* 2)哈希类型hash:map格式
* hset
* hget
* hgetall
* 3)列表类型list:linkedlist格式.支持重复元素
* 1push/rpush
* 1pop/rpop
* lrange start end
* 4)集合类型set:不允许重复元素
* sadd
* 5)有序集合类型sortedset:不允许重复元素,且元素有顺序
* zadd
*/
public class JedisTest {
/**
* * 检查redis是否存活
* * @param url 服务器地址
* * @param port 端口
* * @return
*
*/
public static Integer getRedisIsOk(String url, int port) {
int result = 0;
try {
//连接本地Redis服务
Jedis jedis = new Jedis(url, port);
String ping = jedis.ping();
if (ping.equalsIgnoreCase("PONG")) {
System.out.println("redis缓存有效!" + ping);
result = 0;
}
} catch (Exception e) {
System.out.println("redis缓存失败!");
result = 1;
}
return result;
}
@Test
public void test1(){
//1.获取连接
Jedis jedis = new Jedis("localhost",6379);
//new Jedis(),默认为("localhost",6379)
//2.操作
jedis.set("username", "zhangsan");
//可以使用setex()方法储存可以指定过期时间(秒)的 key value
jedis.setex("activecode", 20, "hehe");
//list 存储
jedis.lpush("mylist", "a", "b", "c");
jedis.rpush("mylist", "a", "b", "c");
//获取
List<String> mylist = jedis.lrange("mylist", 0, -1);
System.out.println(mylist);
System.out.println(jedis.lpop("mylist")+" "+jedis.rpop("mylist"));
System.out.println(jedis.lrange("mylist", 0, -1));
jedis.del("mylist");
//set 存储操作 不可重复
jedis.sadd("myset", "java", "php", "c++");
Set<String> myset = jedis.smembers("myset");
System.out.println(myset);
jedis.del("myset");
//sortedset 有序set
jedis.zadd("mysortedset", 20, "张三");
jedis.zadd("mysortedset", 25, "李四");
jedis.zadd("mysortedset", 29, "王五");
jedis.zadd("mysortedset", 24, "秦六");
Set<String> mysortedset = jedis.zrange("mysortedset", 0, -1);
System.out.println(mysortedset);
jedis.del("mysortset");
//3.关闭连接
jedis.close();
}
/**
* redis连接池, jedis中就有连接池jedisPool不需要外部的连接池
*/
@Test
public void test2() {
//0.创建一个配置对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(50);//最大连接数
config.setMaxIdle(10);//最大空闲连接
//1.创建连接池对象
JedisPool pool = new JedisPool(config, "localhost", 6379);//没有直接的config构造方法
//2.获取连接
Jedis jedis = pool.getResource();
//使用
jedis.set("hehe", "heihei");
//关闭
jedis.close();
}
/**
* redis连接池工具类
*/
@Test
public void test3() {
//2.获取连接
Jedis jedis = JedisUtils.getJedis();
//使用
jedis.set("hehe", "houhou");
System.out.println(jedis.get("hehe"));
//关闭
JedisUtils.close(jedis);
}
}
【maven_web】
pro.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.muyu</groupId>
<artifactId>heima</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
<scope>runtime</scope>
</dependency>
<!--druid连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!--jdbcTemplate-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.18.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.18.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.18.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.18.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
<!--beanUtils-->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
<scope>compile</scope>
</dependency>
<!--jackson-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.3.3</version>
</dependency>
<!--javaMail-->
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.3</version>
</dependency>
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<server>tomcat7</server>
</configuration>
</plugin>
<!--jdk编译插件,解决乱码-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
案例(只罗列技术点)
【信息管理案例】
1.是否登陆验证
使用过滤器,对需要验证的资源进行拦截
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//在filter中的request与其他servlet中request是一个
//0.强制转换
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//获取请求资源路径
String uri = request.getRequestURI();
//2.判断登陆资源路径,注意要排除掉css,js,图片验证码等资源,虽然chrome等高级浏览器会缓存css,js等,但是ie不行
if (uri.contains("findNameServlet")||uri.contains("/regist.html")||uri.contains("/login.jsp")||uri.contains("/checkCode") || uri.contains("/loginServlet")|| uri.contains("/css/")|| uri.contains("/js/")|| uri.contains("/img/")) {
//去登陆,必然放行
chain.doFilter(req, resp);
}else{
User loginUser = (User) request.getSession().getAttribute("loginUser");
if (loginUser != null) {
chain.doFilter(req, resp);
}else{
request.setAttribute("login_msg","尚未登录,请登陆");
//由于重定向本质的原因,无法让request数据给下一个页面,如果实在要用,感觉可以用cookie
//response.sendRedirect(request.getContextPath()+"/login.jsp");
request.getRequestDispatcher("/login.jsp").forward(request,response);
//不放行
}
}
}
2.敏感词汇替换为***
使用过滤器,并利用代理模式代理增强request中的相应方法,然后放回代理后的request,在调用相应方法,实际调用的为增前后的方法
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//创建代理对象,增强getParameter方法
ServletRequest proxy_req = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强getParameter,
if (method.getName().equals("getParameter")) {
//增强返回值
String value = (String) method.invoke(req, args);
if (value != null) {
for (String str : list) {
if (value.contains(str)) {
//更改返回值,敏感词汇在init中加载,免得多次加载
value = value.replaceAll(str, "***");
}
}
}
return value;
}
//增强getParameterMap方法
if (method.getName().equals("getParameterMap")) {
//增强返回值
Map<String, String[]> map = (Map<String, String[]>) method.invoke(req, args);
for (String key : map.keySet()) {
String[] values = map.get(key);
for (int i = 0; i < values.length; i++) {
String value = values[i];
if (value != null) {
for (String str : list) {
if (value.contains(str)) {
//更改返回值,敏感词汇在init中加载,免得多次加载
value = value.replaceAll(str, "***");
continue;
}
}
values[i] = value;
}
}
}
return map;
}
//增强getParameterValues方法
if (method.getName().equals("getParameterValues")) {
//增强返回值
String[] values = (String[]) method.invoke(req, args);
for (int i = 0; i < values.length; i++) {
String value = values[i];
if (value != null) {
for (String str : list) {
if (value.contains(str)) {
//更改返回值,敏感词汇在init中加载,免得多次加载
value = value.replaceAll(str, "***");
continue;
}
}
values[i] = value;
}
}
return values;
}
return method.invoke(req, args);
}
});
//放行
chain.doFilter(proxy_req, resp);
}
private List<String> list = new ArrayList<String>();
public void init(FilterConfig config) throws ServletException {
try {
//获取真实路径
ServletContext servletContext = config.getServletContext();
String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
//读取文件
//BufferedReader流创建出来,默认问gbk的编码(本地都默认为gbk)
BufferedReader br = new BufferedReader(new FileReader(realPath));
//每一行添加list中
String line = null;
while ((line = br.readLine()) != null) {
list.add(line);
}
br.close();
// System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
}
}
3.动态sql查询
使用过滤器,并利用代理模式代理增强request中的相应方法,然后放回代理后的request,在调用相应方法,实际调用的为增前后的方法
<!--jsp分页展示页面 -->
<h3>用户信息列表</h3>
<div style="float: left">
<form class="form-inline" method="post" action="${pageContext.request.contextPath}/findUserByPageServlet" >
<div class="form-group">
<label for="InputName">姓名</label>
<input type="text" name="name" value="${condition.name[0]}" class="form-control" id="InputName" placeholder="">
</div>
<div class="form-group">
<label for="InputAddress">籍贯</label>
<input type="text" name="address" value="${condition.address[0]}" class="form-control" id="InputAddress" placeholder="">
</div>
<div class="form-group">
<label for="InputEmail">邮箱</label>
<input type="text" name="email" value="${condition.email[0]}" class="form-control" id="InputEmail" placeholder="">
</div>
<button type="submit" class="btn btn-default">查询</button>
</form>
</div>
<div style="float: right;margin: 5px;">
<a class="btn btn-primary" href="add.jsp">添加联系人</a>
<a class="btn btn-primary" href="javascript:void(0);" id="delSelect">删除所选</a>
</div>
<form id="delForm" action="${pageContext.request.contextPath}/delSelectedServlet" method="post">
<table border="1" class="table table-bordered table-hover">
<tr class="success">
<th><input type="checkbox" id="firstCb" onclick="selectAll(this)"/></th>
<th>编号</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>籍贯</th>
<th>QQ</th>
<th>邮箱</th>
<th>操作</th>
</tr>
<c:forEach items="${pb.list}" var="user" varStatus="i">
<tr>
<td><input type="checkbox" value="${user.id}" name="uid"/></td>
<td>${i.count}</td>
<td>${user.name}</td>
<td>${user.gender}</td>
<td>${user.age}</td>
<td>${user.address}</td>
<td>${user.qq}</td>
<td>${user.email}</td>
<td><a class="btn btn-default btn-sm"
href="${pageContext.request.contextPath}/findUserServlet?id=${user.id}">修改</a>
<a class="btn btn-default btn-sm" href="javascript:deleteUser(${user.id});">删除</a></td>
</tr>
</c:forEach>
</table>
</form>
//servlet方法
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
String currentPage = request.getParameter("currentPage");//当前页码
String row = request.getParameter("row");//每页显示条数
if (currentPage == null || "".equals(currentPage)) {
currentPage = "1";
}
if (row == null || "".equals(row)) {
row = "5";
}
if (Integer.parseInt(currentPage)<=0){
currentPage = "1";
}
//条件查询
Map<String, String[]> condition = request.getParameterMap();
UserService service = new UserServiceImpl();
PageBean<User> pb = service.findUserByPage(currentPage, row,condition);
request.setAttribute("pb", pb);
request.setAttribute("condition", condition);//为了前端展示数据
request.getRequestDispatcher("/list.jsp").forward(request,response);
}
//userDao方法
public int findTotalCount(Map<String, String[]> map) {
String sql = "select count(*) from user where 1=1 ";
StringBuilder sb = new StringBuilder(sql);
List params = new ArrayList();
for (String s : map.keySet()) {
if ("currentPage".equals(s) || "row".equals(s)) {
continue;
}
if (map.get(s)!=null&&!"".equals(s)) {
sb.append( " and " + s + " like ? ");
params.add("%"+map.get(s)[0]+"%");
}
}
//params.toArray()变成数组
// System.out.println(sb.toString());
// System.out.println(params);
Integer count = template.queryForObject(sb.toString(), Integer.class,params.toArray());
return count;
}
【heima案例(黑马旅游网)】
1.页头页脚异步插入
使用ajxa对页头页脚进行也不插入,不用再写冗余代码了
<!--需要插入页面-->
<script type="text/javascript" src="js/include.js"></script>
<body>
<!--引入头部-->
<div id="header"></div>
<!--导入底部-->
<div id="footer"></div>
</body>
<!--include.js文件-->
$(function () {
$.get("header.html",function (data) {
$("#header").html(data);
});
$.get("footer.html",function (data) {
$("#footer").html(data);
});
});
<!--页头页脚页面-->
<header id="header">
<div class="top_banner">
<img src="images/top_banner.jpg" alt="">
</div>
<div class="header_wrap">
</div>
</header>
<!-- 头部 end -->
<!-- 首页导航 -->
<div class="navitem">
<ul id="category" class="nav">
<!--此处展示导航栏种类-->
</ul>
</div>
</header>
<!-- 尾部 start-->
<footer id="footer">
<div class="why_select">
</div>
<div class="company">
<p>版权所有Copyright 2018-2020, All Rights Reserved</p>
</div>
</footer>
2.js读取地址栏数据
使用js中字符串分隔等技术实现对get数据读取
//根据传递过来的参数name获取对应的值
function getParameter(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)","i");
var r = location.search.substr(1).match(reg);
if (r!=null) return (r[2]); return null;
}
3.jQuery异步分页查询(多页处理)
使用ajxa及封装方法巧妙的实现异步分页查询数据且可以为post方式
$(function () {
/*// 获取连接?及后面所携带的值
var search = location.search;//search获取问好后面的值
// 切割获取第二个值(cid)
//split以某字符串分隔
var cid = search.split("=")[1];
*/
// 获取连接?及后面cid、rname的值
var cid = getParameter("cid");
var rname = getParameter("rname");
if (rname){
// 使用uri进行解码,正常显示中文
rname = window.decodeURIComponent(rname);
}
// 当页码加载完成后,调用load方法发送ajax请求,加载页面数据,此处使用局部请求
load(cid,null,rname);
});
// 抽取方法,参数可以设置种类cid,当前页码currentPage,页面条数pageSize,视情况而定
function load(cid, currentPage, rname) {
// alert(rname+typeof rname);调试,通过这个得知,感觉视频上是错的 ,调用load时rname不应该再加\''+ranem+'\'这样会让null由object转成String的null,直接'+rname+'即可
// 发送ajax请求,请求route/pageQuery,传递cid
$.get("route/pageQuery", {cid: cid, currentPage: currentPage,rname:rname}, function (data) {
// 解析pageBean数据,展示到页面上
// 判断搜索框是否有内容
if (!rname || rname == "null"){
$("#search_input").val("");
}else{
$("#search_input").val(rname);
}
// 1.分页工具条数据展示
// 1.1 展示总页码数和总记录数
$("#totalPage").html(data.totalPage);
$("#totalCount").html(data.totalCount);
// 1.2 展示分页页码
var page_lis = "";
var firstPage = '<li οnclick="javascript:load('+cid+',1,'+rname+')"><a href="javascript:void(0);">首页</a></li>';
page_lis += firstPage;
// 计算上一页的页码
var beforeNum = data.currentPage - 1;
if (beforeNum <= 0) {
beforeNum = 1;
}
var prePage = '<li οnclick="javascript:load('+cid+','+beforeNum+','+rname+')" class="threeword"><a href="javascript:void(0);">上一页</a></li>';
page_lis += prePage;
/*
1、仿照百度的页码工具条,一共展示10个页码,能够达到前5后4的效果
2、如果前边不够5个,后边补齐10个
3、如果后边不足4个,前边补齐10个
*/
// 定义开始位置begin,结束位置end
var begin;
var end;
// 设置显示10个页码
if (data.totalPage < 10) {
// 总页码不够10页
begin = 1;
end = data.totalPage;
} else {
// 总页码超过10页
begin = data.currentPage - 5;
end = data.currentPage + 4;
// 如果前边不够5个,则从后边补齐10个
if (begin < 1) {
begin = 1;
end = begin + 9;
}
// 如果后边不够4个,则从前面补齐10
if (end > data.totalPage) {
end = data.totalPage;
begin = end - 9;
}
}
for (var i = begin; i <= end; i++) {
var page_li;
// 判断当前页码是否等于i
if (data.currentPage == i) {
// 若相等,添加一个当前页码样式curPage
page_li = '<li class="curPage" οnclick="javascript:load('+cid+','+i+','+rname+')"><a href="javascript:void(0);">' + i + '</a></li>';
} else {
// 创建页码的li,不带样式
page_li = '<li οnclick="javascript:load('+cid+','+i+','+rname+')"><a href="javascript:void(0);">' + i + '</a></li>';
}
// 拼接字符串
page_lis += page_li;
}
// 计算下一页的页码
var nextNum = data.currentPage + 1;
if (nextNum >= data.totalPage) {
nextNum = data.totalPage;
}
var nextPage = '<li οnclick="javascript:load('+cid+','+nextNum+','+rname+')" class="threeword"><a href="javascript:void(0);">下一页</a></li>';
page_lis += nextPage;
// 计算末页页码
var lastNum = data.totalPage;
var lastPage = '<li οnclick="javascript:load('+cid+','+lastNum+','+rname+')" class="threeword"><a href="javascript:void(0);">末页</a></li>';
page_lis += lastPage;
// 将lis内容设置到ul中
$("#pageNum").html(page_lis);
// 2 列表数据展示
var route_lis = "";
for (var i = 0; i < data.list.length; i++) {
// 获取list数据{rid:1,rname:""}
var route = data.list[i];
var route_li = '';//数据,注意用单引号,就不用了转双引号
route_lis += route_li;
}
$("#route_ul").html(route_lis);
// 每次点击页面后,都滚动到顶部开始浏览
window.scrollTo(0, 0);
});
}
4.BaseServlet反射调用&BeanUtils使用
利用反射和servlet的原理(tomcat只认识servlet,当我们访问自定义的servlet时,会调用service方法,如果没有则调用父类的service方法,直到找到实现的类中执行,Httpservlet中实现了),但是我们可以自定义一个BaseServelet来实现service方法,然后让其他servletd继承BaseServelet,这样我们就可以利用反射来调用相应方法
public class BaseServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// System.out.println("baseServlet中service被执行");
//完成方法的分发(使用反射)
//1.获取请求路径
String uri = request.getRequestURI();// /heima/user/add
//2.获取请求方法名称
//lastIndexOf()读取字符所在位置
//substring(),截取索引之后的,含头不含尾
String methodName = uri.substring(uri.lastIndexOf('/') + 1);
//3.获取方法对象
//要获取对应方法,需要获取该类型的字节码(class)对象,但是不能固定是谁(要不然还是没有简化)
//this代表的是谁调用我,this就是谁
try {
/*但是不安全,可以将要执行的方法变成public
//getDeclaredMethod获取所有方法,包括私有
Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//4.执行方法
//暴力反射
method.setAccessible(true);
method.invoke(this, request, response);*/
System.out.println("执行"+this+" "+methodName+"方法");
Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//4.执行方法
method.invoke(this, request, response);
} catch (NoSuchMethodException e) {
// e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
@WebServlet("/user/*")
public class UserServlet extends BaseServlet {
private UserService service = new UserServiceImpl();
/**
* 验证注册信息
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void registerUser(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
String check = request.getParameter("check");
HttpSession session = request.getSession();
String checkCode = (String)session.getAttribute("CHECKCODE_SERVER");
session.removeAttribute("CHECKCODE_SERVER");
ObjectMapper mapper = new ObjectMapper();
if(checkCode==null||!checkCode.equalsIgnoreCase(check)){
ResultInfo info = new ResultInfo();
info.setFlag(false);
info.setErrorMsg("验证码错误!!!");
String json = mapper.writeValueAsString(info);
response.getWriter().write(json);
return;
}
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println(user);
String json = mapper.writeValueAsString(info);
response.getWriter().write(json);
}
}