Servlet
1).TomCat服务器
常见软件服务器产品:
tomcat apache提供,java代码编写.(运行以来jvm环境);
apache apache提供.LAMP软件架构.(Linux Apache MySQL PHP)
Nginx 服务器反向代理和负载均衡,集群服务器.
TomCat使用:
①部署静态资源.
a在tomcat的webapps下新建文件夹(代表web项目)
b将资源放入web文件夹中.
②启动tomcat
`startup.bat`
③浏览器访问
常见异常:
①端口被占用
异常信息: socket bind faild / JVM Bind
原因: tomcat使用端口被占用.
解决办法: 修改tomcat/conf/server.xml `<connector port="端口">`
②404
异常信息: 客户端请求的资源找不到?
原因: 地址请求的资源和真正服务器的资源路径不符.(不存在, 路径写错了)
解决办法: 按照请求路径和资源部署路径一个一个校对.
URL:
URL: 统一资源定位符.
注意: 服务器端每个资源(HTML CSS 图片 视频 程序其他资源),都有一个唯一的访问路径.
URL: http://ip:port/项目名/资源路径.
应用: 浏览器地址栏
URI: `/项目名/资源路径` 本tomcat内部资源路径
应用: form a link img
<img src="/项目名/图片资源路径"/>
<form action="/项目名...">
</form>
<a href="/项目名/资源路径"></a>
url-pattern: `/资源路径` 本项目内部资源
2).Servlet初始、及常见异常
概念: 一段Java程序,可以运行在tomcat端.
语法: Servlet标准.(接口) JavaEE标准(servlet-api.jar)
接口: interface Servlet{
init(){servlet对象创建的自动调用}
destroy(){servlet对象销毁的自动调用}
service(){//用户访问tomcat服务器的该程序,调用service方法.
// 用户请求后,执行的代码.
}
}
JavaEE提供类: HttpServlet 实现了Servlet接口.
自定义tomcat运行代码:
public class MyServlet extends HttpServlet{
public void service(){
//覆盖servlet的service方法.
}
}
开发第一个Servlet程序:
需求: 显示当前系统时间?
Servlet开发的具体步骤:
①手动部署servlet程序
编写Servlet程序
导入servlet-api的jar.(编写编译java程序使用)
public class FirstServlet extends HttpServlet{
public void service(){
// 1. 获得当前系统时间
// 2. 将时间返回给浏览器(响应给浏览器)
//打印一字符串
PrintWriter pw = resp.getWriter();
pw.println(“这是一个字符串”);
}
}
②将servlet部署tomcat
在tomcat/webapps下创建文件夹(web项目)
在项目下创建创建WEB-INF/classes,将代码带包拷贝在classes下面
③在web.xml描述(全类名+访问路径)
注册servlet信息:
<servlet>
<servlet-name>&名字&</servlet-name>
<servlet-class>全类名</servlet-class>
</servlet>
映射servlet访问路径
<servlet-mapping>
<servlet-name>&名字&</servlet-name>
<url-pattern>/servlet访问路径</url-pattern>
</servlet-mapping>
④启动tomcat
⑤访问servlet,查看执行响应的结果.
`http:ip:port/项目名/web.xml注册的servlet的访问url-pattern`
`http://localhost:8989/web/firstDate`
常见异常[重点]
①405 `Method Not Allowed`
原因: 方法调用错误
解决办法:
a. 方法名是否错误.
b. service方法内,不能调用父类的方法.
②访问servlet变成下载
响应类型设置有问题
`resp.setContentType("text/html;charset=UTF-8");`
③servlet修改后,没有变化.
原因: servlet代码修改,tomcat需要重启,才能生效.
④500错误:
a. classNotFundException: web.xml的servlet的全类名写错.
b. 服务端java代码运行异常.
⑤404 错误;
浏览器访问地址:
不存在
地址写错(浏览器地址栏, url-pattern不一致,)
tomcat启动就报错(tomcat启动失败)
3).Servlet在MyEclipse中部署、Servlet运行原理、请求参数及请求方式
(1)MyEclipse开发部署Servlet
①新建web project
> 创建web.xml
> 自动创建好对应的目录结构(WEB-INF classes web.xml)
②编写servlet
③编写web.xml
④部署
servers--tomcat8.x---右键---add deployment--选择项目部署
Servlet生命周期 [面试]:
概念: servlet创建时机和活跃使用时机,销毁时机.
interface Servlet{
init(){} //对象创建执行
service(){} //浏览器请求到servlet,提供服务的运行的方法.
destroy(){} //对象销毁执行.
}
① servlet创建
第一个浏览器访问servlet,对象会被创建
一个Servlet类只会创建一个servlet对象.
②servlet服务
浏览器每次访问都会调用service方法.
③servlet销毁
tomcat关闭,销毁servlet对象
重点:
Servlet对象只有一个单实例,面向多线程(用户)访问,**线程不安全**.
①如果servlet有属性, service方法中对属性的操作,加锁.
②要求: Servlet中不要添加数据属性
(2)Servlet执行原理
浏览器向tomcat发出url的http请求: http://ip:port/web项目名/servlet的url-pattern
tomcat服务器:
①获得url的项目名, 从本tomcat下的webapps下找到对应文件夹.
②根据url中servlet的url-pattern,从web.xml找到 servlet-name, 找到servlet-class被访问的servlet的全类名
③Class<?> clazz = Class.forName("Servlet的全类名");//获得servlet的类对象.
④Servlet servlet = (Servlet)clazz.newInstance();//创建出了类的对象(Servlet),
tomcat内部管理servlet
Map<String,Servlet> map = ....;
map.put("url-pattern",servlet);
⑤tomcat先调用 `servlet.init()`方法,(servlet第一被访问)
map.contains("url-pattern")//--true;
⑥`servlet.service(req,resp)`调用servlet的service方法;
⑦服务器将响应结果返回给浏览器.
⑧浏览器发出第二次请求.
⑨tomcat会直接根据url-pattern,找到servlet对象,调用servlet.service方法.
map.get("url中的url-pattern");
(3)Servlet请求参数
概念: 浏览器请求servlet携带的数据,叫做请求参数
Servlet接收请求参数:
`request.getParameter("表单元素的name")//接收名字对应单个数据的参数`
`request.getParameterValues("表单元素的name")//获得一个名字对应多个值,返回值String[]`
(4)浏览器请求Servlet的方式
①浏览器地址栏。也可以添加数据例如xxxx/xxxxxx/xxxx?username=“值”&password=“值”
②form表单(的action)请求Servlet
`<form action="servlet的路径(URI)">`
③超链接的href.
`<a href="servlet的路径(URI)"></a>`
补充小技巧:
使用浏览器监控浏览发出请求的请求参数 (F12调试)
名字=值;
4).请求参数乱码问题、Servlet请求转发、Request作用域、请求重定向(Redirect)、总结跳转方式
(1)请求参数乱码问题
①Post提交乱码:
了解: tomcat接收数据默认编码: `ISO-8859-1`
接收: req.setCharacterEncoding("UTF-8")
发送: resp.setContentType(“text/html;charset=UTF-8”);
注意: 设置编码,在接收请求参数之前设置
② Get提交乱码:
方式:
form action="" method="get"
超链接携带的数据.
浏览器发送请求参数
修改tomcat的conf/server.xml中`<connector URIEncoding=”UTF-8” />`
(2)Servlet各司其职
请求转发(foward)
作用: **多个Servlet配合完成一个功能**
核心特点:
①是服务器(当前web项目)内部发送的流程跳转*
②forward请求转发连接的多个servlet,处于一个请求过程中.
代码:
RequestDispatcher rdp = request.getRequestDispatcher("转发后的下一个servlet的url-pattern/其他资源的url-pattern路径");//获得转发器.
rdp.forward(req,resp);//foward转发.调用转发动作.
补充:
跳转情况:
`servlet-->Servlet`
`servlet--->HTML(JSP)`
(3)Request作用域
概念: JavaEE提供的存储数据(命名属性)的空间.
命名属性: 名字---值
生命周期: 一次请求过程.[备注:请求转发的servlet正好处于一次请求过程]
存: `request.setAttribute("名字",值/数据/对象/xxx)`
取: `request.getAttribute("名字")`
(4)请求重定向(Redirect)
核心特点:
①服务器(web应用)外部跳转。
②通知浏览器,自动去请求下一个要跳转的页面或者Servlet(不需要用户操作)
③重定向连接的servlet或者资源,处于两个不同的请求过程。
④请求重定向后的页面和浏览器的地址一致。
代码实现:
resp.sendRedirect("/项目名/资源路径url-pattern");
//通知浏览器自动请求"/项目名/资源路径url-pattern"
(5)总结跳转方式
请求转发(foward) 请求重定向(Redirect)
原理(本质) 服务器(Web项目)内部跳转 服务器(Web项目)外部跳转
请求过程 1个请求过程 2个不同的请求过程
浏览器显示和地址 不一致 一致
作用域 可以使用request作用域传值 不能使用request作用域传值 [了解:地址?拼接数据]
应用 servlet--->传递数据,使用request作用域,请求转发。一个业务功能中的多个资源要处于一个请求过程中,使用请求转发;servlet跳转的下一个资源属于另一个业务功能,使用请求重定向。
5).会话技术(Cookie、HttpSession)、Session实现原理、解决浏览器禁用Cookie后Session失效问题
会话技术
http协议: 无状态协议,(协议本身不会记录任何信息,两次信息传输之间没有任何关系)
概念: 客户端(浏览器)会话技术。
应用场景: 浏览器记录 登录验证 验证码 购物车(阉割版)
另一种解释: 浏览器和服务器之间,多次交互依然保存数据(状态)的一种机制。(每个浏览器一份)
(1)Cookie
概念: 服务器保存在浏览器上的一小段字符串[key=value]
工作机制:
①服务器tomcat创建
②保存在浏览器
③浏览器每次访问服务器,都会将服务器(web项目)保存在本浏览器上的cookie发送到服务器上。(发送当前服务器保存的cookie)
编码实现:
①创建:
Cookie cookie = new Cookie("key","value");
②将cookie存入浏览器
response.addCookie(cookie);// 将cookie随着响应返回给浏览器.
③其他方法(设置生命周期,设置存活多久)
cookie.setMaxAge(存活时间秒);
④获得浏览器请求携带的cookie信息?
Cookie[] cs = req.getCookies();
cs[0].getName(); //cookie的key
cs[0].getValue(); //cookie的value
总结Cookie的特点
①存在浏览器上的一小段字符串
>缺点: (数据不太安全)
>优点: 分担服务器的压力。(不会占用服务器的任何资源)
②cookie只能保存字符串,不能保存中文。
③cookie生命周期: (跨多次请求)
设置: setMaxAge(秒)
10 存活10s
0 删除cookie
-1 设置cookie浏览器关闭之前。
默认: 浏览器关闭,cookie丢失。
④cookie和浏览器(用户)一一对应。
(2)HttpSession
概念: 服务器会话技术。
核心工作机制: 服务器为每个**浏览器分配的一个一一**对应的存储空间。
详细: 浏览器第一次访问web应用服务器,服务器分配一个session对象,该浏览器第二次后再访问,服务器直接将原有sessino对象分配给该浏览器。
HttpSession的特点:
①存放在服务器
②每个浏览器和session一一对应
③HttpSession的生命周期夸多次请求依然存在。
HttpSession 相关的API:
①属性: id.
②获得session: `request.getSession()`
浏览器第一次访问: 创建session对象。
浏览器第二 三...次访问: 获得原有的session对象给你。
HttpSession作用
**作用域,存储命名属性**
存:`session.setAttribute("name",值)`
取: `session.getAttribute("name")`
移除:`session.removeAttribute("name")`
特点:
①浏览器一一对应
②跨多次请求依然存在
③存放在服务器
应用场景(强制登录/登录验证):
需求:某些资源(HTML,Servlet)的访问需要用户登录之后才能访问,否则,强制用户去登录页面登录?
基本思路: web项目服务器记住用户(登录)
Session失效时机(补充):
①浏览器关闭,session失效。
②session默认保留30分钟。 【浏览器和服务器之间,超过30分钟没有请求】
--当前项目的web.xml中修改
<session-config>
<session-timeout>60</session-timeout>
</session-config>
③主动失效: `session.invalidate()` 将所有Session失效
应用: 用户退出登录:
`session.removeAttribute("user")`
`sesssion.invalidate()`
Cookie和Session对比[笔试]
Session和Cookie的相同点
和浏览器一一对应。
生命周期跨多次请求依然存。
Session和Cookie的不同点:
Cookie:
存在浏览器
cookie只能存储字符串,不能存汉字.(缺点)
cookie数据容易通过浏览器直接查看,不太安全。(缺点)
Session:
存在于服务器端
session可以存对象,可以存入任何类型。(优点)
session数据保存服务器,相对安全。(优点)
session中数据过多,侵占服务器内存资源(对服务器运行造成压力)[缺点]
应用场景分析:
用户私密信息(Session)
用户浏览器过的商品信息(cookie保存)
(3)Session实现原理
机制:
浏览器第一请求服务器web项目,会为该浏览器创建一个session对象。获得session的id,并且将id以cookie的形式写回到浏览器。以后每次浏览器,请求服务器都会自动携带该cookie(JsessionId)信息,tomcat通过获得cookie中名字为jesessionid的cookie的value值,和内部所有的session对象匹配,找到对应的session对该浏览器使用。
内部代码咋实现(局部代码):
①浏览器第一请求服务器:
HttpSession session = new XxxxSession();
String id = session.getId();
//将session保存在服务器内存中(集合)
Map<String,HttpSession> map = new ConcurrentHashMap<String,HttpSession>();
map.put(id,session);
Cookie ck = new Cookie("jsessionid",id);
resp.addCookie(ck);
②浏览器第二次(以后)请求服务器
Cookie[] cks = req.getCookies();
for(Cookie c:cks){
if(c.getName().equals("jsessionid")){
String sessionId = c.getValue();
//根据sessionid找到对应的session对象
HttpSession session = map.get(sessionId);
}
}
(4)用户禁用Cookie (了解)
导致session失效,解决办法?
总结:
对所有超链接+表单等一切请求服务器的url路径,全部进行url重写。
方法: `String 重写后的url = resp.encodeUrl(原url地址)`
纠错: `重写url;jsessionid=1234asdf1234`;
6).Filter过滤器
Filter过滤器: Servlet中提供的技术,可以过滤浏览器发出的请求,并且决定放行请求还是中断请求。
编码步骤:
①自定义一个java类,实现Filter接口
public class EncodingFilter implements Filter{
init(){}
destroy(){}
//请求经过filter要执行的代码
doFilter(FilterChain chain){
//放行请求之前
chain.doFilter(req,resp);//放行请求。中断:不要调用
//响应回来的代码,例如:资源的控制
}
}
②在web.xml中注册信息
<!-- 注册filter信息 -->
<filter>
<filter-name>filter名字</filter-name>
<filter-class>filter全限定名</filter-class>
</filter>
<filter-mapping>
<filter-name>filter名字</filter-name>
<url-pattern>/被过滤请求的servlet或者html等资源的url-pattern</url-pattern>
</filter-mapping>
生命周期(了解):
①创建: tomcat启动
②销毁:tomcat关闭
Filter的url-pattern的写法:
①写多个<url-pattern>资源</url-pattern>
②`/*`---过滤所有请求(统配) <url-pattern>/*</url-pattern>
③`*.do`---过滤请求以.do的请求,在要过滤的servlet的全类名后加”.do”
然后配置filter:<url-pattern>*.do</url-pattern>
④`/xxxxooaa/*` ----过滤路径中的url-pattern部分,以/xxxxxooaa开头的请求
<url-pattern>/目录/*</url-pattern>
应用:
可以为所有servlet设置编码格式
7).ServletContext容器、监听器(ServletContextListener/HttpSessionListener/ServletRequestListener)
(1)ServletContext
(容器)作用域: 一个web应用只有一个ServletContext对象。
创建:tomcat启动创建 销毁: tomcat关闭
编程:
① 获得servletContext对象:
`ServletContext ctx = session.getServletContext()`
② 存: `ctx.setAttribute("name",值)`
③ 取: `ctx.getAttribute("name")`
④移除: `ctx.removeAttribute("name")`
全局参数:
web.xml启动加载完毕会将信息存入servletContext
1. 在web.xml书写常亮配置
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
2. 从servletContext中获得常亮配置
String value = ctx.getInitParameter("encoding"); //“UTF-8”
web应用内流的相对路径:
`String 真实路径 = ctx.getRealPath("/项目名下的相对路径")`
项目名的动态获取(补充):
String ctxtPath = request.getContextPath();// "/项目名"
使用: 跳转路径: /项目名
(2)监听器
事件编程模型
概念:
事件源: 发生事件的对象本身,源头。
事件: 具体发生事情事件。
监听器: 监听事件源上发生的具体的事件,如果发生,会触发对应的代码执行。
监听器:
SerletContextListener: 监听ServletContext对象的创建和销毁
HttpSessionListener: 监听HttpSession对象创建和销毁
ServletRequestListner: 监听ServletRequest对象创建和销毁。
编码:
①自定义一个类实现ServletContextListener:
public class MyContextListener implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("context----销毁!!!!!!!!!!!!");
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("context----创建!!!!!!!!!!!!");
}}
②web.xml注册:
<listener><listener-class>全类名</listener></listener>
应用:
需求: 监控在线用户数量?
在HttpSession监听器中,监听session创建与销毁。