JavaWeb - J2EE - JavaEE
Http协议:超文本传输[服务器、客户端]协议
请求:
请求行:请求提交方式[get/post]、请求的地址URI
请求头:请求的客户端信息 map
请求体:提交的请求参数 - post [get提交参数,在URI中?]
响应:
响应行:响应状态码
响应头:Map 服务器信息
响应体:响应内容[页面、JSON]
---------------------------------------------------------------------------
Tomcat:web应用服务器 - 软件 port:8080
web应用:动态网络资源
Java代码完成的可以在浏览器上运行的应用程序
部署在web应用服务器上的
tomcat编码:ISO8859-1
目录
Tomcat - apache 纯Java写 开源 免费
bin:命令、工具
startup bat sh
./startup.sh
shutdown
lib:类库 jar
servlet-api
jsp-api
conf:配置文件
server.xml - 服务器配置
web.xml - tomcat中所有的web应用,不能修改
webapps:web应用 多个
目录/文件[html、css、js、.class、jar...]
work:工作目录
jsp 翻译文件
temp:临时文件
logs:日志
backup:备份
web应用与web工程对比
web应用:webapps里面的目录
根目录
|- web静态资源
html\css\js\图片...
|- WEB-INF - 目录是受保护的[客户端不能直接访问]
|- web.xml - 当前web应用配置信息
schame 约束
|- classes - 类路径 - src源码编译过来
|- lib - 库 jar[mysql、c3p0、dbutils]
|- META-INF 元信息
web工程:eclipse 代码
src: 资源目录
java代码、配置文件
JRE System Library:jdk 类库
Apache Tomcat v8.5:tomcat类库
build: 类路径 - 工程
classes
src源代码编译后的文件
WebContent/WebRoot:web应用根目录
web静态资源
META-INF
WEB-INF
|- lib
|- web.xml - 服务器启动时就会读取
服务器启动完成后,检查控制台有没有报错
-----------------------------------------------------------------------------------------
Servlet三个规范:Servlet、Filter、Listener
web应用:
默认主页:index、default
JavaEE提供HTTP协议,web开发规范 Servlet JSP
Servlet:Server + applet
Servelt 规范用来接收请求,返回响应
实现Servlet步骤:
1.自定义类,实现Servlet接口
2.重写service方法
3.到web.xml文件中注册Servlet
<servlet>
<servlet-name>自定义名字
<servlet-class>完整类名
<servlet-mapping>
<servlet-name>一致的名字
<url-pattern>资源路径 /xx
4.访问测试:
http://localhost:8080/web01/a/hi
------------------------------------------------------------------------------------------------
Servlet生命周期:- 单例模式
init: 对象创建时,初始化调用
默认第一次接收请求创建
可以修改为服务器开启时创建 <load-on-startup>n
service:服务核心方法,用来接收请求。每一次请求接收时调用
destroy:对象销毁,服务器关闭
什么时候创建?
默认第一次接收请求时创建
可以设置为服务器开启时创建
<load-on-startup>10</load-on-startup>
什么时候销毁?
服务器关闭销毁
----------------------------------------------------------------------------------------------
一共有23种设计模式
单例模式:
应用执行过程当中,只有一个对象的模式,叫做单例模式
懒汉模式、饿汉模式
工厂模式:简单工厂、抽象工厂、工厂方法
结合反射
spring
装饰者模式
代理模式:spring
单例模式:线程不安全。(一般放方法,不放成员变量)
整个应用运行过程中,只有一个对象生成
Singleton s1 = Singleton.print();
1.构造器私有
private Singleton() {}
2.提供可以获得对象的静态方法
public static Singleton print() {}
3.保证对象只new一次,将对象设置为static的
private static Singleton single
懒汉模式:用的时候再创建(使用对象时,再创建对象)
private static Singleton single = null;
public static Singleton print() {
synchronized (Singleton.class) {
if (single == null) {
single = new Singleton();
}
}
return single;
}
饿汉模式:加载时直接创建(类加载时,对象就已经创建好)
private static Singleton single = new Singleton();
public static Singleton print() {
return single;
}
----------------------------------------------------------------------------------------------------------------------------
ServletConfig : Servlet相关配置,一个Servlet对应一个config
<!-- 初始化配置parameter -->
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</init-param>
ServletConfig 作用:
// 作用一:获得Servlet对应的name
// <servlet-name>HelloKitty</servlet-name>
String servletName = config.getServletName();
// 作用二:获得Servlet自己的初始化配置信息
String driver = config.getInitParameter("driver");
// Enumeration<String> names = config.getInitParameterNames();
// 作用三:获得ServletContext对象
ServletContext context = config.getServletContext();
--------------------------------------------------------
HttpServlet 类 间接实现了 Servlet接口
实现了service方法,调用了自己的service方法
判断请求方式,调用 doGet/doPost
----------------------------------------------------
匹配
<!-- 方式一:完全匹配 -->
<!-- <url-pattern>/HelloServlet</url-pattern> -->
<!-- 方式二:目录匹配 - Filter/SpringMVC -->
<!-- http://localhost:8080/web02/hello/kitty.html -->
<url-pattern>/hello/*</url-pattern>
<!-- 方式三:后缀匹配 - 管理系统 -->
<!-- <url-pattern>*.html</url-pattern> -->
结论:所有的资源都是由 Servlet 来处理的
html jpg css js jsp .. .do ..Servlet
有一个默认的Servlet来接收web.xml中匹配不到的资源
全局的web.xml中配置了缺省/默认的Servlet来接收其他请求
DefaultServlet
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
-----------------------------------------------------------------------------------
ServletContext -> ApplicationContext
应用上下文:属于应用,一个应用只有一个上下文
创建:服务器开启
销毁:服务器关闭
1.获得ServletContext
config.getServletContext()
2.request.getServletContext();
小范围对象可以获得大范围对象的引用
3.servlet.getServletContext();
<!-- 应用全局参数 -->
<context-param>
<param-name>location</param-name>
<param-value>c3p0-config.xml</param-value>
</context-param>
ServletContext 和 ServletContext域
域对象:存取数据使用 Map<String, Object>
域范围:参考生命周期(服务器开始到结束)
setAttribute(key, value)
value getAttribute(key)
removeAttribute(key);
ServletContext 作用:
ServletContext context = request.getServletContext();
// 作用一:获得应用名 /web02
// "/we02/hello" - 用path 替换/web02
String path = context.getContextPath();
// 作用二:获得应用的全局参数
String parameter = context.getInitParameter("location");
// 作用三:通过应用中资源的相对路径获得资源的绝对路径
// 1.src/a.txt
// 2.WebContent/b.txt
// 3.WEB-INF/c.txt
// 4.工程/d.txt - 不存在应用中
String a = context.getRealPath("WEB-INF/classes/a.txt");
String b = context.getRealPath("b.txt");
String c = context.getRealPath("WEB-INF/c.txt");
// 作用四:作用域对象
// 向域中存数据
context.setAttribute("name", "zhangsan");
// 从ServletContext域中取数据
Object attribute = context.getAttribute("name");
// 从域中删除对应数据
context.removeAttribute("name");
-----------------------------------------------------------------------------
Response响应
// 1.响应行 - 状态码 200 404 304 302 500
response.setStatus(304);
int status = response.getStatus();
// 2.响应头 - Map<String, String>
setHeader("location", "url")
setIntHeader(name, value)
setDateHeader(name, value)
// 如果原来有,覆盖掉值
response.setHeader("name", "lisi");
// 新增一个值,不论之前有没有
response.addHeader("name", "zhangsan");
// response.getHeader("name");
response.getWriter().write("hello Bonnie...");
//3.响应体
getOutputStream(); // 文件复制/下载
// 通知浏览器打开文件的方式 - 以附件形式
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
getWriter();
write print println
setCharacterEncoding(); // response缓冲区编码
// meta
setContentType("text/html;charset=utf-8");
// 302 -> 重定向:当前Servlet做完了,继续下一次任务,使用重定向
// response.setStatus(302);
// location:url地址
// response.setHeader("location", "/web02/Servlet1Demo");
// 重定向最终代码,路径:绝对路径,从应用名开始 "/应用名/资源名"
response.sendRedirect("/web02/Servlet1Demo");
// 注意:1.字节流和字符流不能同时使用
// 2.通过response打开的流,不能手动关闭,tomcat会负责关闭
// OutputStream os = response.getOutputStream();
// 设置response缓冲区编码 ISO8859-1
// response.setCharacterEncoding("utf-8");
// 设置响应类型 - 方式、编码
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
// 写到客户端 -> 页面
writer.println("哈哈");
----------------------------------------------------------------------------
Request请求:HttpServletRequest -> ServletRequest
行:uri method
getMethod()
getRequestURI()
getRequestURL()
getQueryString() -- 了解
客户端IP地址
头:客户端信息 Map
referer、user-agent
getHeader("user-agent/referer") cookie
getIntHeader()
getDateHeader()
体:post参数
post: form method="post"
get: 直接访问、超链接、重定向、form method=“get”
获得请求参数 name=value name:value
String getParameter(name)
String[] getParameterValues(name)
集合 getParameterNames()
Map<String, String[]> getParameterMap()
-> BeanUtils.populate();
get/post 提交方式区别:
1.get参数在url上
post参数在请求体中
2.get参数有大小限制
post参数没有大小限制
3.get参数格式只能是字符串
post支持多种类型 - 文件
4.编码:
get 和tomcat编码一致 - 可以改
post ISO8859-1 - 不能改
Tomcat默认编码就是ISO8859-1
和eclipse进行了绑定 - 通过eclipse 开启的服务器 utf8
独立的tomcat单独启动 iso8859-1
// 1.获得request行信息 method uri?get参数 GET/POST
String method = request.getMethod();
// 2.URI/URL post/get获得内容一样
String requestURI = request.getRequestURI();
String requestURL = request.getRequestURL().toString();
// 3.get提交方式的参数 - ?后面部分
// post方式得到的是null
String queryString = request.getQueryString();
// 1.获得request头信息 cookie referer
String agent = request.getHeader("user-agent");
// 获得客户端地址
String addr = request.getRemoteAddr();
// referer:资源来源 - 通过哪里访问的
String referer = request.getHeader("referer");// 防盗链
// 判断是自己服务器访问的该链接
if(referer == null || referer.startsWith("http://localhost:8080")) {
response.setContentType("text/html;charset=utf-8"); --> 服务器显示为utf-8编码
response.getWriter().write("新闻三:今年七夕没有520红包");
} else {
// 跳转到首页
response.sendRedirect("/web03/index.html");
}
// URI/URL ? 中文 解码 -> 编码 -> 通用
// name=%E7%AB%A0%E4%B8%89 -> 恢复
String queryString = request.getQueryString();
// URLEncoder.encode(queryString, "utf-8"); - 解码
queryString = URLDecoder.decode(queryString, "utf-8"); - 编码
// 请求设置编码
request.setCharacterEncoding("utf-8"); - post
// 设置响应类型为纯文本 或者 application/json
response.setContentType("text/plain;charset=utf-8");
// request可以直接获得应用名
// request.getServletContext().getContextPath();
request.getContextPath();
// 获得文件对应的mimetype类型
String mimeType = request.getServletContext().getMimeType("jpg");
// 接收请求参数
// 设置request 解析编码 - post有效
// request.setCharacterEncoding("UTF-8");
// 1.一个name对应一个value
// radio(单选)不选,获得null
// text/password/textarea/date 不填,获得""
String name = request.getParameter("name");
// ---- 解决乱码 get编码设置为ISO8859-1
name = new String(name.getBytes("ISO8859-1"),"utf-8");
// 2.一个name对应多个value [ check多选 select下拉列表 ]
String[] hobbies = request.getParameterValues("hobby");
// 3.
Map<String, String[]> parameterMap = request.getParameterMap();
request作为域对象使用
request域 - 一次请求
setAttribute
getAttribute
removeAttribute
-------------------------------------------------------------------
转发:通过reqeust
我们可以认为转发的过程是同一个请求和响应
共用同一个request 的 map域
但是,本质而言是不同的对象
结论:直接接收请求的资源才可以使用getParameterxx方法
// 同一次请求的跳转 -> 转发 forward
//RequestDispatcher dispatcher = request.getRequestDispatcher("");
//dispatcher.forward(request, response);
// 转发给Servlet2Demo - 应用内部转发,默认是当前同一个路径 "/资源名"
request.getRequestDispatcher("/Servlet2Demo").forward(request, response);
客户端路径:http://ip:port/appName/资源名
/appName/资源名 - 在同一个服务器中
href src action 都是客户端路径
服务器端路径:转发, 应用内部转发
默认是当前同一个应用
/资源名 - 同一个应用中
-----------
封装对象
-- 参数太多、属性太多,使用BeanUtils
BeanUtils.populate(user, request.getParameterMap());
-- id是32位字符串,使用UUID
UUID.randomUUID().toString()
user.setUid(uid.replace("-", "")); - 去除四个 -,剩余32位。设置uid
---------------------------------------------------------------------------------------------
文件下载案例
// 获得请求参数 /web02/download/a.flv
String filename = request.getParameter("filename");
String name = null;
// 解决浏览器不支持中文的问题
// agent就是请求头中的user-agent
String agent = request.getHeader("user-agent");
if (agent.contains("MSIE") || agent.contains("TRIDENT") || agent.contains("EDGE")) {
// IE浏览器
name = URLEncoder.encode(filename, "utf-8");
name = name.replace("+", "%20");
} else if (agent.contains("Firefox")) {
// 火狐浏览器
BASE64Encoder base64Encoder = new BASE64Encoder();
name = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
} else {
// 其它浏览器
name = URLEncoder.encode(filename, "utf-8");
}
// 告诉浏览器,文件是以附件形式打开,不是直接解析
response.setHeader("Content-Disposition", "attachment;filename=" + filename);
// 获得要下载文件的绝对路径
String path = request.getServletContext().getRealPath("download/" + filename);
// 打开输入流
InputStream in = new FileInputStream(path);
// 获得输出流
OutputStream out = response.getOutputStream();
// 复制
byte[] bs = new byte[1024];
int len = -1;
while((len = in.read(bs)) != -1) {
out.write(bs, 0, len);
}
in.close();
out.close();
-----------------------------------------------------------------------------------------------
编码问题:
请求编码 Tomcat默认编码就是ISO8859-1
get 和tomcat编码一致 - 可以改
post ISO8859-1 - 不能改
// 设置response缓冲区编码 ISO8859-1
// response.setCharacterEncoding("utf-8");
// 设置响应类型 - 方式、编码
// response.setContentType("text/html;charset=utf-8");
// 设置响应类型为纯文本 或者 application/json
response.setContentType("text/plain;charset=utf-8");
// 设置request 解析编码 - post有效
// request.setCharacterEncoding("utf-8");
// ---- 解决乱码 get编码设置为ISO8859-1
name = new String(name.getBytes("ISO8859-1"),"utf-8");
--------------------------------------------------------------------------------------------------
代理主键、自然主键
id:
序列 sequence.nextVal
自增长 auto_increment
uuid
-----------------------------------------------------------------
会话:
第一次请求发送过来,开始会话
多次请求
关闭客户端结束会话
HTTP协议无状态,客户端本身没有有效信息给服务器
-----------------------------------------------
Cookie:存在客户端 -- 一次会话
1.服务器接收到请求
2.服务器通过response把内容存储在客户端
Cookie默认是会话结束就清除的
可以设置Cookie的持久化
// 1.创建Cookie map 不支持中文
Cookie cookie = new Cookie("name", "bao");
// 设置cookie的持久化时间,单位是秒
cookie.setMaxAge(Integer.MAX_VALUE);
// 携带路径;访问哪些资源会把cookie携带到服务器
// 默认携带路径 - 当前目录,不是当前应用
// /web4/Servlet3Demo
// cookie.setPath("/"); // -- 当前服务器中所有应用
cookie.setPath("/web04"); // -- 当前应用
// 2.把Cookie带到客户端
response.addCookie(cookie);
// 结论:只有name和path一致的时候,才算同一个cookie
// 获得客户端通过request携带过来的Cookie
Cookie[] cookies = request.getCookies();
---------------------------------------------------------------------------------------------------------------
Session:存在于服务器。存数据。取数据
域对象范围:一次会话
如果第一次调用,服务器会给客户端先创建一个session,返回
如果再次调用,直接返回原先创建好的session
Session什么时候创建:
第一次调用request.getSession()
什么时候销毁:
注意:不是会话结束session就销毁的!!
服务器关闭(非正常关闭)
手动销毁 session.invalidate()
超时,默认30分钟 - 全局web.xml
<session-config>
<session-timeout>1</session-timeout>
</session-config>
// 1.获得session对象。小范围获得大范围
HttpSession session = request.getSession();
// 2.存数据
session.setAttribute("age", 19);
String jsessionid = session.getId();
// 3.JSESSIONID持久化
Cookie cookie = new Cookie("JSESSIONID", jsessionid);
cookie.setPath(request.getContextPath());
cookie.setMaxAge(Integer.MAX_VALUE);
response.addCookie(cookie);
// 手动销毁
// session.invalidate();
// 获得Session中保存验证码
String checkcode_session = (String) request.getSession().getAttribute("checkcode_session");
------------------------------------------
小结:域范围从大到小
ServletContext:服务器应用
session:一次会话 - 登录后的用户信息、购物车
request:一次请求 - 转发
cookie:存客户端、JSESSIONID、用户名、密码
---------------------------------------------------------------------------------------------------------
JSP:Java Server Page
JSP可以接收请求、返回响应,本质就是Servlet
JSP - 工作文件 tomcat -> work
原理:JSP运行之前,在第一次访问JSP文件时翻译成java代码
xx.jsp -> xx_jsp.java
间接继承HttpServlet,JSP本质就是Servlet
<html> --> out.write()
<% %> --> 翻译后,出现在service方法中
<%= %> --> out.print()
<%! %> --> 会被翻译成servlet的成员的内容
jsp注释可见范围:JSP代码、翻译后的Java代码、、html页面源码
<!-- --> html注释 :JSP代码、翻译后的Java代码、html页面源码
// java注释 :JSP代码、翻译后的Java代码
<%-- --%> jsp注释 :JSP代码
-----------------------------
JSP:
html标签
css
js
3种java脚本
3种注释
<%@ %> JSP指令
JSP内置对象
JSP动态标签
EL表达式
JSTL标签
---
<%@ %> JSP指令
page:属性最多
language:java、php、c#
contentType:response.setContentType(text/html;charset=UTF-8);
pageEncoding:包含了contentType 当前页面编码
extends:继承
session:默认true,false-不能在jsp中使用session
errorpage:出现异常后,转发到的页面
isErrorPage:默认false
isELIgnored:默认false,el有效
import:导包
include:包含子页面 - 静态包含
格式:<%@ include file="被包含的文件地址"%>
file:页面路径
taglib:引入标签库
格式:<%@ taglib uri="标签库地址" prefix="前缀"%>
uri:库的资源路径
prefix:前缀
JSP内置对象:在JSP脚本中可以直接使用的对象 9个
HttpServletRequest request
HttpServletResponse response
ServletContext application
HttpSession session
PageContext pageContext
Writer out
ServletConfig config
page -> this xx_jsp.Servlet
exception -> 抓取到的异常 isErrorPage = "true"
out: 输出流 缓冲区
buffer = "0kb" - 关闭out缓冲区,内容直接写到respons缓冲器
pageContext:域对象 - 当前页面
可以操作其他三个域
pageContext.setAttribute("name", "zhangsan", PageContext.APPLICATION_SCOPE);
pageContext.getAttribute("name", PageContext.APPLICATION_SCOPE)
findAttribute(name)
pageContext.findAttribute("name")
-- 依次从pageContext域,request域,session域,application域四个域中,寻找name对应的值,直到找到为止
-- 从小到大
四大作用域的总结:
page域:当前JSP页面范围
request域:一次请求
session域:一次会话
application域:整个web应用
可以获得其他8大隐式对象
pageContext.getRequest()
pageContext.getSession()
JSP动态标签:
<!-- 动态包含 -->
<jsp:include page="jsp1.jsp"></jsp:include>
<!-- 转发 -->
<jsp:forward page="/pageContext1.jsp"></jsp:forward>
静态包含和动态包含的区别?
静态包含:<%@include file=""%>
翻译出一个java文件,编译,运行
动态包含:<jsp:include page="">
翻译出两个java文件,编译,运行
EL表达式:Expression Language
目的:为了从域中获得数据
取代get方法 - 减少Java脚本
语法:${表达式 }
内置对象:11个 -- 了解
<!-- applicationScope/sessionScope/requestScope/pageScope -->
<!-- 取代四个域中的getAttribute(name) -->
applicationScope ---- ${applicationScope.name }<br>
sessionScope ---- ${sessionScope.age }<br>
requestScope ---- ${requestScope.name }<br>
pageScope ---- ${pageScope.name }<br>
<!-- pageContext.findAttribute(name) -->
${name } ---- 最常用用法
${1+1 } -> 打印 2
${list == null ? 1:2 }
<!-- 为空=true,不为空=false
null 一定是空, ""/空集合 -> true
判断依据,值是不是有效值,内容是否为空
-->
${empty list }
<!-- EL内置对象 -->
<!-- pageScope/requestScope/sessionScope/applicationScope -->
<%-- request.getParameter("username") --%>
${param.username } <br>
<%-- request.getParameterValues("username") --%>
${paramValues.username[1] }<br>
<!-- request.getHeader("user-agent") -->
user-agent: ${header['user-agent'] }<br>
Host: <%-- ${header.host } --%> ${header['host'] }<br>
initParam: ${initParam.aaa }<br>
<!-- cookie 相当于 Map<name, Cookie> -->
${cookie.JSESSIONID.value}<br>
${pageContext.request.contextPath } /web05
例:
<%
// EL获得Map<String,User>的值
Map<String, User> userMap = new HashMap<String, User>();
User u1 = new User("lucy", 18);
User u2 = new User("tom", 20);
User u3 = new User("jack", 25);
User u4 = new User("marry", 30);
User u5 = new User("john", 33);
userMap.put("u1", u1);
userMap.put("u2", u2);
userMap.put("u3", u3);
userMap.put("u4", u4);
userMap.put("u5", u5);
request.setAttribute("userMap", userMap);
// EL获得Map<String, List<User>>的值
Map<String, List<User>> listMap = new HashMap<String, List<User>>();
List<User> userList1 = new ArrayList<User>();
userList1.add(u1);
userList1.add(u2);
userList1.add(u3);
userList1.add(u4);
List<User> userList2 = new ArrayList<User>();
userList2.add(u1);
userList2.add(u2);
userList2.add(u3);
userList2.add(u4);
List<User> userList3 = new ArrayList<User>();
userList3.add(u1);
userList3.add(u2);
userList3.add(u3);
userList3.add(u4);
listMap.put("userList1", userList1);
listMap.put("userList2", userList2);
listMap.put("userList3", userList3);
request.setAttribute("listMap", listMap);
%>
<!-- EL表达式 . 出来的是什么类型 -->
${userMap.u3.name } -- ${userMap.u3.age }
${listMap.userList2[3].name } -- ${listMap.userList2[3].age }
JSTL标签
<!-- JSTL标签库使用
1.导库 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
12.使用,添加前缀
13.配合EL表达式使用
-->
------------------------
<!-- if(a==1) if判断
test:判断条件
-->
<c:if test="${user == null }">
<a href="#">请登录</a>
</c:if>
<c:if test="${!empty user }">
${user.name }
</c:if>
----------------------------------------------------------------------
<!-- for(int i = 0; i < 10; i++) {} for循环
var="i" -> 等同于在当前页面定义了一个变量i,并且存入page域中
-->
<c:forEach begin="0" end="9" step="1" var="i">
${i }
</c:forEach>
-------------------------------------------------------------------------------------------------
<!-- for(String str : list) {} --> 遍历List<String>的值
<!-- 等同于,从List中依次迭代元素,取名叫str,存入page域中 -->
<c:forEach items="${list }" var="str">
${str }
</c:forEach>
----------------------------------------------------------------------------------------------------------------
<c:forEach items="${userList1 }" var="user"> 遍历List<User>的值
${user }<br>
</c:forEach>
--------------------------------------------------------------------------------------------
<!-- entrySet entry:键值对 -->
<c:forEach items="${strMap }" var="entry"> 遍历Map<String,String>的值
${entry.key } ---- ${entry.value }<br>
</c:forEach>
-----------------------------------------------------------------
<!-- entrySet entry:键值对 -->
<c:forEach items="${userMap }" var="entey"> 遍历Map<String,User>的值
${entey.key } ---- ${entey.value }<br>
</c:forEach>
-----------------------------------------------------------------------------------------------------------------
javaEE的开发模式
model1: JSP + javaBean
model2: Servlet + jsp + javaBean
Servlet:擅长写Java代码
JSP:擅长页面
MVC模式:
M:model----模型 javaBean:封装数据
V:view----视图 JSP:单纯进行页面的显示
C:controller----控制器 Servlet:获取数据--对数据进行封装--传递数据--指派显示的jsp页面
JavaEE三层架构
web:前端交互 servlet + jsp + javabean
service:业务处理
dao:数据库操作 -> dbutils c3p0 jdbc
----------------------------------------------------------------------------------------------------------------------------------------
Filter 过滤器:在Servlet之前进行的拦截/过滤
过滤、拦截请求
url-pattern
实现过滤器:
1.自定义类实现Filter接口
2.着重实现doFilter方法
3.注册 - 参考servlet
<filter>
<filter-name>MyFilter1</filter-name>
<filter-class>a_filter.MyFilter1</filter-class>
<init-param>
<param-name>name</param-name>
<param-value>lucy</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<!-- 进入哪些路径之前进行过滤 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器中可以有响应内容,也可以不放行
放行后的响应内容也生效
多个过滤器,顺序由filter-mapping的注册顺序决定 - chain
chain.doFilter(); - 递归
每一个过滤器都要放行,才能进入Servlet资源
没有放行意味着拦截了,放行意味着去了真正想访问的资源 -- chain.doFilter(request, response);
配置文件详解:
<filter-mapping>
<filter-name>MyFilter2</filter-name>
<!-- 等同于url-pattern,只能精确匹配,可以和url-pattern同时使用 -->
<!-- <servlet-name>Servlet1Demo</servlet-name> -->
<!-- 方式一:精确匹配 -->
<url-pattern>/Servlet1Demo</url-pattern>
<!-- 方式二:目录匹配 -->
<!-- <url-pattern>/hello/*</url-pattern> -->
<!-- 方式三:后缀匹配 -->
<!-- <url-pattern>*.jsp</url-pattern> -->
<!-- 拦截请求方式
REQUEST:直接访问,超链接、重定向 - 默认
FORWARD:转发时
ERROR:errorPage="error.jsp"
INCLUDE:包含
可以多个选项共存
-->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
-------------------------
创建、销毁时间
ServletContext: 服务器开启、关闭
Servlet: 默认第一次接收请求、服务器关闭
Session: 第一次getSession()、3种方式
Request、Response: 一次请求
Filter: 服务器开启、关闭
--------------------------------------------
ServletConfig:
1.获得servlet-name
2.获得初始化init-param
3.获得ServletContext
FilterConfig:
1.获得filter-name
2.获得初始化init-param
3.获得ServletContext
Filter功能:公共代码提取
-- 解决请求参数乱码:post get
让Servlet专注于获得参数即可
getParameter(name);
-------------------------------
代码:解决请求参数乱码 -- 装饰者模式
HttpServletRequest request -- 被装饰对象
MyRequest -- 装饰对象
// 应该重写ServletResquest接口
// j2ee,提供了一个从来重写Request的类
class MyRequest extends HttpServletRequestWrapper{
// 使用被装饰对象来包装
private HttpServletRequest request;
// 重写getParameter方法
public MyRequest(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
// 1.获得乱码
String parameter = request.getParameter(name);
// 2.解决乱码
try {
parameter = new String(parameter.getBytes("ISO8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 返回中文
return parameter;
}
}
将对象方法增强 - 装饰者模式:目的-为了增强对象的功能
被装饰对象(原始对象)、装饰对象(功能增强后的对象)
1.装饰对象拥有被装饰对象相同的父接口
2.重写要增强的方法
3.使用被装饰对象 来 包装一个新对象 - 构造器
-----------------------------------------------------------------------------------------
Listener监听器:用或者不用,不影响动作的发生
作用:可以知道某个动作发生,并且做出对应的响应
种类:6 + 2 -> 接口
6: 3种域对象有关 request、session、application
2: 对象感知监听器,对象和session的关系
步骤:
1.自定义类,实现xxxListener接口
2.注册
<listener>
<listener-class>c_listener.MyServletContextListener</listener-class>
</listener>
监听三大域对象的创建与销毁的监听器:request、session、application 3种
例:
ServletContextListener:创建-服务器启动,销毁-服务器关闭;等同于监视服务器开启、关闭
作用:
1.初始化的配置、参数加载 -> Spring
2.任务调度
contextInitialized:ServletContext创建时调用
contextDestroyed:ServletContext销毁时调用
任务调度:contextInitialized中
Timer timer = new Timer();
// 3000 -> 过3000毫秒,程序正式启动
// 10000 -> 周期性时间,1天
timer.schedule(new TimerTask() {
public void run() {
System.out.println("又过生日了!");
}
}, 3000, 10000);
监听三大域对象的属性变化的监听器:request、session、application 3种
例:
ServletContextAttributeListener
内容改变:setAttribute(); removeAttribute();
attributeAdded(ServletContextAttributeEvent scae)
可以获得被监听的对象;可以获得改变的属性内容,添加的属性name-value
attributeRemoved(ServletContextAttributeEvent scae)
attributeReplaced(ServletContextAttributeEvent scae)
再一次name,setAttribute(),scae.getValue()返回的是改变前的内容
--------------------------
对象感知监听器,对象和session的关系
1.绑定、解绑 HttpSessionBindingListener valueBound - 绑定 valueUnbound - 解绑
2.钝化、活化 HttpSessionActivationListener sessionWillPassivate - 钝化 sessionDidActivate - 活化
步骤:对象的实体类实现xxListener接口
与session中的绑定的对象相关的监听器(对象感知监听器) 2种
绑定与解绑的监听器HttpSessionBindingListener
钝化与活化的监听器HttpSessionActivationListener
钝化: Session存在服务器 sessionWillPassivate(HttpSessionEvent se)
服务器关闭后,session中保存的内容还在 - 服务器本地硬盘
服务器关闭后,session对象在不在?- 内存中对象不在
钝化:session数据Object -> 序列化 -> 硬盘字节 Serializable
设定Session钝化时间,规定session多久不用,数据保存在硬盘,节省内存空间 -> 服务器优化
可以通过配置文件 指定对象钝化时间 --- 对象多长时间不用被钝化
<Context>
<!-- maxIdleSwap:session中的对象多长时间不使用就钝化,单位为分钟 -->
<!-- directory:钝化后的对象的文件写到磁盘的哪个目录下,配置钝化的对象文件在
work/catalina/localhost/钝化文件 -->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="bonnie" />
</Manager>
</Context>
活化: 服务器重新开启 sessionDidActivate(HttpSessionEvent se)
本地硬盘中的session数据重新恢复到内存的过程
-------------------------------------------------------------------------------------------------------------------
Ajax
JS原生的Ajax技术
$("#btn0").click(function(){
// 1.创建引擎对象
var xmlhttp = new XMLHttpRequest();
// 2.绑定监听
xmlhttp.onreadystatechange = function(){
// 5.接收响应数据
if(xmlhttp.readyState==4 && xmlhttp.status==200){
alert(xmlhttp.responseText);
$("#span").html(xmlhttp.responseText);
}
}
// 3.绑定地址
xmlhttp.open("GET", "/web08/Servlet1Demo", true);
// 4.发送请求
xmlhttp.send();
});
JQuery的Ajax技术 3种
- $.get(url, [data], [callback], [type])
- $.post(url, [data], [callback], [type])
url:代表请求的服务器端地址
data:代表请求服务器端的数据(可以是key=value形式也可以是JSON格式)
callback:表示服务器端成功响应所触发的函数(只有正常成功返回才执行)
type:表示服务器端返回的数据类型(JQuery会根据指定的类型自动类型转换);常用的返回类型:text、json、html等。
get与post代码相同
$("#btn2").click(function(){
// 局部刷新\提交请求 - ajax
$.get(
"/web08/Servlet1Demo", // url
// "name=zhangsan&age=18&gendar=f",
// 请求参数提交 可以name=value,也可以json
{
"name": $("#name").val(),
"age": 19,
"gendar": 'f'
},
function(data){ // 响应成功的回调函数,data - 相应内容
$("#span").html(data.gendar);
},
// "text" // 响应类型 text/json
"json"
);
});
3.$.ajax( { option1:value1,option2:value2... } ); 最底层的方法
async:是否异步,默认是true代表异步
data:发送到服务器的参数,建议使用JSON格式
dataType:服务器端返回的数据类型,常用text和JSON
success:成功响应执行的函数,对应的类型是function类型
type:请求方式,POST/GET (ajax建议使用GET)
url:请求服务器端地址
error:失败的回调函数,对应的类型是function类型
$("#btn1").click(function(){
$.ajax({
url: "/web08/Servlet1Demo",
data: {
"name": $("#name").val()
}, // 请求参数
success: function(data){
$("#span").html(data.age);
},
dataType: "json",
type: "GET", // 默认get
async: false // 默认异步true,false - 同步
});
});
自定义校验规则
<script type="text/javascript">
$(function(){
// 自定义校验规则
$.validator.addMethod("checkUser", function(value, element, params){
var pass = false;
// value:输入内容,需要给数据库对比
$.ajax({
url: "/web08/CheckUserServlet",
data: {
"username": value
},
success: function(data){
// data.isExists -> true -> 校验不通过
// data.isExists -> false -> 校验通过
pass = !data.isExists;
},
dataType: "json",
async: false // 必须同步
});
return pass; // 返回true表示校验通过
});
// 信息校验
$("#regForm").validate({
rules: {
username: {
required : true,
minlength : 6,
maxlength : 20,
checkUser : true
},
password: {
required : true,
minlength : 6,
maxlength : 20
}
},
messages: {
username: {
required : "用户名不能为空",
minlength : "用户名长度不能小于6",
maxlength : "用户名长度不能大于20",
checkUser : "用户名已存在"
},
password: {
required : "密码不能为空",
minlength : "密码长度不能小于6",
maxlength : "密码长度不能大于20"
}
}
});
});
</script>
将java对象,变为json对象格式的字符串
List<Product> list = ps.SearchAllProduct(pname);
Gson gson = new Gson();
String json = gson.toJson(list);
--------------------------------------------------------------------------------------------------
类加载器:3种
源代码 -> 编译 -> .class -> 加载 -> 方法区
类加载器加载类按顺序加载,相同类不能重复加载。(双亲委派机制)
引导类加载器 - 加载都是最基础的文件
扩展类加载器 - 加载都是基础的文件
应用类加载器 - 三方jar包和自己编写java文件
类加载方式:
1.使用的时候
2.ProductDao.class
3.Class.forName("java.lang.String");
每一个类加载,都会得到一个它对应的Class对象
操作字节码对象 -> 反射 Class
类中所有的成员[属性、方法、父类、接口、异常...] 都可以通过字节码对象获得
反射理论中,基本数据类型和引用类型完全不同 如 int 和 Integer 不同
反射
反射操作的是字节码对象 java.lang.String
代码1:
// String.class;
// "hello".getClass();
// Class.forName("java.lang.String");
Class cla = String.class;
// 调用对象的属性,方法
// 1.创建对象 - 构造器
// new String("haha")
String str = (String) cla.newInstance(); // 无参构造器
// 调用
System.out.println(str);
----------------------------------------------------------
代码2:
Class clz = Class.forName("a_reflect.User");
// 默认就是使用可以访问的无参构造器
// User user = (User) clz.newInstance();
// System.out.println(user);
// 如果需要使用其他构造器
Constructor constructor = clz.getConstructor(int.class);
// 使用构造器
User u1 = (User) constructor.newInstance(34);
System.out.println(u1);
// 可以获得所有声明的构造器,包括私有的
Constructor c2 = clz.getDeclaredConstructor();
// 设置私有可见
c2.setAccessible(true);
User u2 = (User) c2.newInstance();
System.out.println(u2);
----------------------------------------------------------------------------
代码3:
// 通过反射调用User对象的方法
Class clz = User.class;
// 调用传2个参数的有参构造器
Constructor constructor = clz.getConstructor(int.class, String.class);
User u = (User) constructor.newInstance(23, "lucy");
// User u = new User(23, "lucy");
// 1.获得User对象的方法 方法名为study,参数为String
Method method = clz.getMethod("study", String.class);
// 2.调用方法,并且获得返回值 u为对象,“java”为传的参数
String ret = (String) method.invoke(u, "java");
System.out.println(ret);
-------------------------------------------------------------------------------------------------
工厂模式:简单工厂、抽象工厂、工厂方法
-- 提供方法,为了获得对应的对象
配置文件 - key-value
String - 类名 - 反射
获得对应的对象
FactoryUtils
public class FactoryUtils {
private static Properties pros;
static{
pros = new Properties();
try {
pros.load(new FileInputStream(FactoryUtils.class.getResource("Factory.properties").getFile()));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object getInstance(String classKey) {
// 1.通过key,获得对应的类名
String className = pros.getProperty(classKey);
// 2.获得对应的Class对象
try {
Class<?> clz = Class.forName(className);
// 3.创建对象,并返回
return clz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
Factory.properties:
ProductDao = dao.impl.ProductDaoImpl
使用工厂模式:
ProductDao pd = (ProductDao) FactoryUtils.getInstance("ProductDao");
--------------------------------------------------------------------
注解 Annotation
注解作用:取代配置文件 Spring
注释:在阅读程序时清楚----给程序员看的,JVM自动跳过
注解:给jvm看的,给机器看的,JVM可以识别
JDK1.5三个注解
@Override:告知编译器此方法是覆盖父类的。只能放方法上,没属性
@SuppressWarnings:压制警告,被修饰的类或方法如果存在编译警告,将被编译器忽略。可放在类、成员变量、方法、局部变量上。属性类型 String[]
deprecation,忽略过时
rawtypes,忽略类型安全
unused,忽略不使用
unchecked,忽略安全检查
null,忽略空指针
all,忽略所有
@Deprecated:标注过时。放在任何位置,没属性
元注解:JDK 2个 - 标注注解的注解。作用:限制定义的注解的特性
@Target 注解添加位置可以设置:类、属性、方法、构造器。。。。
FIELD : 字段上可用此注解
METHOD : 方法上可以用此注解
TYPE : 类/接口上可以使用此注解
@Retention 注解可见范围: 源码、字节码、运行时
SOURCE : 注解在源码级别可见
CLASS :注解在字节码文件级别可见
RUNTIME :注解在整个运行阶段都可见
注解属性:
规定有且只有一个必须有值的属性,名为value时,属性名才可以省略
例:
public @interface MyAnnotation{
int value();
// 属性可以有默认值
String name() default "haha";
}
可以写为 @MyAnnotation(10)
---------------------------------------------------------------------------------------------
分页查询
public PageBean<Emp> findEmpPageBean(String currentPageStr, String pageSizeStr) {
int currentPage = 0;
int pageSize = 0;
if (currentPageStr == null) {
currentPage = 1;
} else {
currentPage = Integer.valueOf(currentPageStr);
}
if (pageSizeStr == null) {
pageSize = 3;
} else {
pageSize = Integer.valueOf(pageSizeStr);
}
int totalCount = ed.getCount();
List<Emp> list = ed.findEmpByPage(currentPage, pageSize);
PageBean<Emp> pb = new PageBean<Emp>(totalCount, currentPage, pageSize);
pb.setList(list);
return pb;
}
public int getCount() {
String sql = "select count(1) from emp";
try {
long count = (Long) qu.query(sql, new ScalarHandler());
return (int)count;
} catch (SQLException e) {
e.printStackTrace();
}
return 0;
}
public List<Emp> findEmpByPage(int currentPage, int pageSize) {
// 第一个?:从第几条开始 0
// 第二个?: pageSize
// currentPage = 3,pageSize=2
String sql = "select * from emp limit ?,?";
int startRow = (currentPage-1) * pageSize;
try {
return qu.query(sql, new BeanListHandler<Emp>(Emp.class), startRow, pageSize);
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}