BS项目
一、WEB项目的演变:
1.发展规律:
由单击向网络发展;由CS向BS发展
2、CS和BS的区别
1)CS(Client Server): 客户端服务端程序, 客户端需要单独开发,用户需要单独下载并安装
2)BS(Browser Server):浏览器服务器程序,客户端不用单独开发,用户不用单独安装
二、Servlet介绍(*)
扩展Web服务器功能的组件规范
1、服务器如何保存并返回一个网页
1)静态网页
无论谁看其内容都一样 百科,新闻,服务器直接存HTML,直接返回HTML即可
2)动态网页
不同人看到的内容有差异 淘宝、微博,服务器保存一个组件,动态给每个用户拼一个网页
在Java语言中这个组件就是Servlet
组件:满足规范的对象
2、Servlet的特点
是服务器端的组件,满足sun的规范,可以动态拼资源(HTML/IMG等)
术语:处理HTTP协议
3、什么是Servlet
sun推出的用于在服务器端处理HTTP协议的组件
三、服务器
1、名称
Java服务器,WEB服务器,Java WEB服务器, Servlet容器
2、本质
是一个软件
它和浏览器是平级的关系
3、举例
Tomcat (Apache)
JBoss WebLogic WebSphere
4、Tomcat的使用方式
1)、单独使用(项目上线时)
配置好JAVA_HOME
下载及安装
doc.tedu.cn
2)启动tomcat:
Linux:打开tomcat/bin,在终端输入chmod+x*sh
Linux:打开tomcat/bin,在终端输入./startup.sh
widows:打开tomcat/bin,双击startup.bat
3)访问tomcat:在浏览器输入http://localhost:8080
4)关闭tomcat/bin,在终端输入./shutdown.sh
windows:打开/tomcat/bin,双击shutdown.bat
回车后看到一只猫就代表成功啦
5)若配置失败需要重来:window->preference->server->runtime
弹出框中在右侧选择tomcat,然后点击remove案例
在Eclipse中将自动生成的Servers项目删除
重新按照步骤进行配置即可
2、通过Eclipse调用(开发时)
window->preference->server->runtime
add,create a new...
最后项目列表出现servers,在show view中点击servers,在控制台点击三角按钮打开
注意只能启动一个,要不然冲突
五、Servlet开发步骤
1、创建WEB项目
必须具备标准的WEB目录
/webapp/WEB_INF/web.xml
2、导入jar包:
1)使用maven导入
使用maven搜索javaee,javaee.api
2)使用tomcat自带的包
选择项目,右键点击Properties
弹出框里选择Targeted Runtimes,勾选Apache Eomcat apply
看Java resources中 libraies有tomcat包就ok了
3、开发Servlet
1)编写Servlet
创建package 创建一个类,名为XxxServlet 继承HttpServlet,从而间接的实现了Servlet接口
重写父类的service()方法
2)配置Servlet
先声明类,并给它取别名
再通过别名引用此类,给它取一个访问路径
4、部署(拷贝)
在Servers视图下,选择Tomcat
右键点击Add and Remove
在弹出框内将左边的待部署项目移动到右侧
启动tomcat即可
5、访问
格式:http://ip:port/项目名/网名
例子:http:localhost:8080/servlet1/ts
买一个域名和ip地址绑定
补充:tomcat常见使用问题:
4,常见的错误及处理方式
(1)404
1)错误原因:
a,应用没有部署。
b,请求地址写错。
按照http://ip:port/appname/url-pattern
c,<servlet-name>不一致。
(2)500
1)错误原因
a,程序运行时出错。
b,<servlet-class>写错。
(3)405
1)错误原因
服务器找不到处理方法。
(4)在启动tomcat时看到如下的错误 addrss alread in use,JVM_BIND:8080
2)产生原因
重复启动tomcat造成8080端口的冲突
可能其他软件占用了8080端口
3)解决方案
启动原因:打开tomcat/bin目录,关闭
其他软件:打开server.xml,在65行修改tomcat端口
建议修改为8088,8089,关闭后修改,修改后重启才生效
一、HTTP协议
(HypeText Transfer Protocol)
1、什么是HTTP协议
就是一个规范(w3c)
w3c制定的一种应用层协议,
用来定义浏览器与web服务器之间如何通信以及通信的数据格式
2、如何通信
建立连接 发送请求 接受响应 断开连接
一次请求一次连接,降低服务器的压力
3、数据格式
1)请求数据:
请求行:请求的基本信息
消息头:请求数据的描述
实体业务:具体的业务数据
2)响应数据
状态行:响应的基本信息
消息头:响应数据的描述
实体业务:具体的返回数据
4、对开发者的要求
1)不用开发者处理的地方
浏览器自动打包请求数据
浏览器自动发送请求数据
服务器自动打包响应数据
服务器自动发送响应数据
2)需要开发者处理的地方
提供具体的请求中的业务数据
提供具体的响应中的返回数据
通过request处理请求数据,通过response处理响应数据
开发者会使用request和response就行了
启动报错看配置文件web.html
---------------------
面试是一个沟通,jdbc用到Iterator
设计模式有哪些? 迭代器?
--------------------------
单选框name两个用途,互斥跟这个
处理请求重写父类的方法service
--------------------------------
多写if语句,多控制,nullPointer异常是重大异常
---------------------------------
提交之后null:说明注册网页和接受参数时的name不一致
三、Servlet运行原理
组件:满足规范的对象
由服务器运行
四、请求方式
1、什么是请求方式
就是浏览器向服务器发送数据的方式
需要掌握众多方式中的2种:GET+POST
GET:请求指定的资源
POST:向指定的资源提交需要处理的数据
2、GET
采用请求路径传参
参数在传递过程中可见,导致隐私性差(有密码不能使用这个方法)
路径可以容纳的数据有限,只能传少量数据
所有的请求默认都是GET请求
3、POST
采用实体内容传参
参数在传递过程中不可见,隐私性好
实体内容专门用来传数据,大小没有限制
在form上加上method="post"
4、观察GET和POST请求
在浏览器上按快捷键F12看NetWork选项
解决乱码问题
发送接收数据有可能乱码
有三种方式:(图片)
希望大家解决乱码问题时提前做好以下工作,不要等到出现乱码的时候才想到解决办法。
写程序前提前想到会出乱码,后面出乱码的可能性会很小。等到出现了乱码,就很难分清到底是谁造就了乱码,就算你知道了,想改正都晚了。
JSP页面乱码:
<%@ page language="java" contentType="text/html;charset=utf-8" %>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
表单提交乱码
GET:
打开<tomcat_home>\conf目录下server.xml文件,找到对8080端口进行服务的Connector组件的设置部分,给这个组件添加一个属性:
URIEncoding="GBK"。修改后的Connector设置为:
<Connector port="8080" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" <SPAN style="COLOR: #ff0000">URIEncoding="utf-8"</SPAN> />
POST:
在获得参数或响应前加上:
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
一般情况下都会写一个过滤器(课程中会讲解)
PS:正常情况下提交方式都会使用POST请求,除非非用GET不可,GET不管从安全,容量上讲都不是最好的选择,而且中文参数解决也比较麻烦,因此我们尽量使用POST请求,
对于GET请求,尽管有时候我们使用修改Tomcat服务器配置的时候依然不能解决,那个时候不防采取编码解码的方法
以上为正常请求,但是如果碰到有文件上传的时候,那么上面的方法是无法解决的
这个时候我们可以在获得参数的时候注意一下FileItem 对象的一个重载方法:即获得参数的方法:fileItem .getString() ,fileItem .getString(String)
如果遇到有中文的参数,可以选择fileItem .getString(String) 方法,譬如:fileItem .getString(“UTF-8”)
数据库:
最好的情况(我们可控的)能在安装数据库时就能够设置数据库的编码
1、如果数据部是我们安装的,也无法获得权限,这个时候我们可以通过程序控制数据库的编码问题:
url?useUnicode=true&characterEncoding=utf8
2、以上依然解决不了乱码问题可以修改一下你所用的库,表,及字段的编码属性
修改数据库编码的命令是:ALTER DATABASE test DEFAULT CHARACTER SET utf8 COLLATE utf8_bin
修改表的编码的命令是:
ALTER TABLE category DEFAULT CHARACTER SET utf8 COLLATE utf8_bin
修改表中字段的编码的命令是:
ALTER TABLE test MODIFY dd VARCHAR( 45 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
对于DB初始化即你要从终端向数据库插入数据的时候,请详细参考我给你们的mysqlCN.pdf,请注意这里的各属性的含义,个人认为初始化不需要在终端进行,
最好能有相关工具,譬如mysql-front。以及MyEclips里自带的工具,这样能够避免很多不必要的问题
JS方面的乱码 可以通过编码解码的方法:详细参考JS的API中的JScript 方法中A-E 中的decodeURI方法及encodeURI方法
遇到中文乱码的时候,首先要确定在哪里出现的乱码问题:
1、在获得页面参数的时候把值打印出来==》判断是否表单提交问题
2、对持久化层用中文进行测试数据库==》判断是否数据出现的问题-
补充:
1、JavaBean
满足如下规范的类:
有包 有默认的构造器 要实现序列化接口 (有get/set方法)
复习彻底,根据项目复习,学以致用 思路跟流程
---------------------------
处理流程:
//1.接受参数
//2.处理业务
//3.输出响应
GET和POST使用场景(建议)
查询数据时用GET,因为通常查询条件较少
提交数据(表单)时用POST,因为通常提交的数据较多
三、重定向:
不能命令,降低耦合度,使用重定向
是平级关系,不要直接调用,不利用代码的维护
可以解决:
1、不同网站之间跳转问题
2、一个网站之间独立组件的跳转
四、路径
1、什么是路径
这些代码得部署在服务器上运行
服务器上的代码的访问路径,不是代码存放的位置
2、URI和URL的区别:
1)狭义理解
只在Java项目中理解URI和URL
URI:绝对路径 URL:完整路径
从表面上看URI包含了URL
2)广义理解(*)
在任意的WEB项目中理解URI和URL
URI:资源的名称(各种名字) URL:资源的真名
URI包含了URL
3、如何配置Servlet访问路径
1)精确匹配
举例:/abc
只有/abc才能访问此Servlet 此Servlet只能处理这一耳光请求
适合规模很小的项目
2)通配符 举例:/*
所有的路径都能访问此Servlet
此Servlet能处理所有请求
适合一个项目只写一个Servlet
3)后缀 不允许以/开头 举例:*.hi
所有以hi为后缀的请求都能访问此Servlet
此Servlet能处理多个请求
适合一个项目写少量的几个Servlet
五、Servlet的生命周期
默认首次访问实例化并初始化 调用,之后只调用不再实例化初始化
可以启动时实例化并初始化,处理请求时调用service,关闭时销毁
Tomcat实例化Servlet只会调用默认的构造器
可以用init()初始化一些数据
1、默认首次访问Servlet时tomcat会实例化它
2、可以改为启动tomcat时就实例化Servlet
<!-- 启动时加载此Servlet,中间的数字是加载的顺序 -->
<load-on-startup>1</load-on-startup>
3、第1、2、4步只执行一次,所以HiServlet是单(个实)例(每一个类型Servlet只实例化一次)
4、第3步可以执行多次,每次处理请求都执行
5、意义:当需求规定在什么时刻做什么处理时,开发者好有的放矢(知道在哪个方法写代码)
,servlet的生命周期
(1)什么是servlet的生命周期?
servlet容器如何创建servlet对象,如何对其
进行初始化,调用其方法来处理请求,以及如何
销毁servlet对象的整个过程。
(2)生命周期的四个阶段
1)实例化
a,什么是实例化?
容器创建servlet对象。
b,什么时候实例化?
情况1:容器收到请求之后,才会创建。
注:容器在默认情况下,对于某个servlet,
只会创建一个实例。
情况2: 容器启动之后,立即创建。
<load-on-startup>大于等于0的整数</load-on-startup>
值越小,容器越先创建。
2)初始化
a,什么初始化
容器在创建好servlet对象之后,会立即调用该对象的init方法。
b,如何实现自己的初始化处理逻辑
b1,GenericServlet提供了init方法的基本实现:
将容器传递过来的ServletConfig对象保存下
来,并且提供了一个getServletConfig方法来
获得该对象。
b2,只要override init()方法即可。
c, 访问servlet的初始化参数
step1,配置初始化参数
<init-param>
<param-name>company</param-name>
<param-value>北京达内科技</param-value>
</init-param>
step2,
String ServletConfig.getInitParameter(
"company");
d,init方法只会执行一次。
3)就绪
a,什么是就绪
容器收到请求之后,会调用servlet对象的service方法。
b,HttpServlet的service方法实现过程:
依据请求方式调用相应的doxxx方法(比如,请求方式为get,则调用doGet方法,这些doxxx方法并没有完整实现,需要开发人员去override)。
注:
选择1(建议):override doGet/doPost
选择2: override service
4)销毁
a,什么是销毁
容器将servlet对象从容器当中删除掉。
容器在删除servlet对象之前,会先调用该对象的destroy方法。
b,destroy方法用于释放资源,该方法只会执行一次。
(3)生命周期相关的几个类与接口
a,Servlet接口
init(ServletConfig config);
service(ServletRequest req,
ServletResponse res);
destroy();
b,GenericServlet抽象类实现了Servlet接口中的部分方法(init,destroy)
c,HttpServlet抽象类继承了GenericeServlet,实现了service方法。
六、ServletConfig和ServletContext
1、它们的作用
有些时候我们需要给Servlet预置一些参数,可以自己写配置文件,自己调用工具读取
但Sun给我们提供了这两个工具,从web.xml中读取数据,是数据的载体
2、它们的区别
1)config
和Servlet是1对1的关系
tomcat在初始化每个Servlet前会给它创建1个config
调用HiServlet.init()前给它创建1个config
调用HelloServlet.init()前给它创建1个config
如果想给某个Servlet预置数据,使用config
2)context
和Servlet是1对多的关系
Tomcat在启动时就创建唯一的一个context
所有的Servlet都可以共享这个对象中的数据
如果想给多个Servlet预置数据,使用context
3、它们的应用
1)config
假设我们要开发一个网页游戏
当用户数超出最大在线人数时要排队
登录时判断是否已达到最大人数
登录:LoginServlet
最大人数:maxOnline,可以配置
该参数只给LoginServlet自己用,用config读取即可
//tomcat创建Servlet的逻辑:
//LoginServlet s=new LoginServlet();
//ServletConfig c=new ServletConfig();
//c.加载数据();//web.xml加载数据
//s.init(c);
2)context
软件内有很多查询功能,都带有分页功能
每页显示的行数size是常量,并且可配置
该数据在多个查询功能之间共用,使用context读取
//tomcat启动时就会创建唯一的context
//并且会调用它的方法加载web.html中的公用参数
//context是全局的,任何Servlet都可以使用
存在配置文件里的是常量
4、context的特殊用法
前提:之前使用config和context读取的是常量
而context还有能力读写变量
用该对象读写的变量是可以被所有Servlet共用的
setAttribute()/getAttribute()
案例:开发流量统计的功能,无论访问哪个功能,流量+1
由于流量是变量,并且在多功能间共用,所以用context读写
class InitServlet extends HttpServlet
该Servlet不负责处理具体的业务
* 只用来在tomcat启动时初始化数据
* 一般WEB项目都有1-2个这样的Servlet
要设置这个Servlet为启动时初始化。
<servlet>
<servlet-name>init</servlet-name>
<servlet-class>web.InitServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
//tomcat启动时会优先创建context,然后再创建Servlet
5、总结
当需要给Servlet预置参数时使用这样的对象
若参数只给一个Servlet使用,用config
若参数给多个Servlet共用,用context
一、Servlet核心接口与类
protected void service(HttpServletRequest req,HttpServletResponse res)
声明的接口,传入的是tomcat实现的类的实例requestFacade、responseFacaed
不同服务器的实现类可能不一样,所以声明接口
-----------------------------------------
找类快捷键:ctrl+shift+f
先找类通过箭头定位到包
看一个类的结构:window-showview-outline
找方法快捷键ctrl+o
方法前面的绿色代表public
黄色代表protected
红色代表private
-------------------------------
TttpServlet的结构
使用绿色的Service,传入的参数ServerRequest/需要自己转型成httpServletRequest/,再使用(httpServletRequest里面的方法多)
使用sun重载的黄色的Service里面传入的就是httpServletRequest,不用我们转,
tomcat调用Service过程:
tomcat调用的是HiServlet的绿色的Service。这个Service是从父类(HttpServlet)中的)继承的,所以程序运行到了父类
但绿色的Service参数不好用,需要转型,它帮我们重载了黄色的Service,帮我们转型了(方便我们使用)
转型之后调用黄色的Service(我们所重写的Service是被二手调用的)(现在程序跳转到了子类)
然后我们所重写的黄色的Service又调用doGet() doPost()方法(do方法有局限性,只能处理一种请求)
这样我们可以在doGet() doPost中单独处理不同的请求
一串调用,调哪个都可以,多种选择
重载,然后互相调用,调用哪个都可以解决
三、Servlet线程安全问题
同时修改同一份数据会出现线程安全问题
1、同时修改局部变量
局部变量存于栈内,每个线程有自己的栈帧,此时没有线程安全问题
2、同时修改成员变量
成员变量存于堆内,所有线程共享这样的数据,此时存在线程安全问题
3、解决方案:
加锁
测试线程安全:白盒,黑盒
用网络延迟的方式模拟一下并发
-----------------------------------------
加super根不加super的区别??
加super继承父类重写的方法?
-----------------------------------
JSP
服务端动态页面技术的组件规范
访问JSP的完整的请求过程
1、include
<!-- 此JSP被其他网页引用,是其他网页的一部分,不必写出完整的结构 -->
<p><%=now %>></p>
<!-- 引入一个JSP ,相当于将JSP的内容复制到此处-->
<%@include file="time.jsp" %>
2、JSP运行原理
3、翻译的过程
4,如何写一个jsp文件?
step1,创建一个以".jsp"为后缀的文件。
step2,在文件里面,添加如下的内容:
(1)html(css,js):直接写。
(2)java代码:
1)java代码片断 <% java语句; %>
2)jsp表达式 <%= java表达式%>
(3)隐含对象
1)什么是隐含对象?
在jsp文件里面,可以直接使用的对象,比如
jsp隐含(内置)对象(面试题)
1、request(*)-HttpServletRequest
2、respons -HttpServletResponse
3、out -JSPWriter -类似于PrintWriter
4、config -ServletConfig
5、application --ServletContext
6、Exception -Throwable -jsp翻译成的Servlet所抛出的异常
7、session(*) -HttpSession
8、page -Object -相当于this,用来指代翻译成的哪个Servlet
9、pageContext(*) -PageContext 是管理者,通过它可以获取其他8个隐含对象
如何在jsp上使用隐含对象
<%Object user=session.getAttribute("user");%>
<%=session.getAttribute("user")%>
2)为什么可以直接使用这些隐含对象?
容器会自动生成获得这些对象的代码。
(4)指令
1)什么是指令?
通知容器,在将jsp文件转换成servlet类时, 做一些额外的处理,比如导包。
2)指令的语法
<%@ 指令名称 属性=属性值%>
3)page指令
a, import属性:导包 比如 <%@page import="java.util.*"%>
b, contentType属性:设置response.setContentType的内容。
c, pageEncoding属性:告诉容器jsp文件的编码(有些容器,在读取jsp文件的内容时,默认为按照 iso-8859-1去解码,如果jsp文件里面包含了中文,会出现乱码)。
5,jsp是如何执行的?
step1,容器将jsp文件转换成一个servlet类。
html(css,js) -----> service方法里,使用 out.write输出。
<%java语句;%> -----> service方法里,照搬。
<%= java表达式%> --->service方法里,使用out.print(java表达式)输出。
step2,容器调用servlet。
二、开发模式
Model1:
Servlet和Jsp里面的代码 java跟HTML耦合度高
Model2:
Servlet和jsp相互配合使用
解引入了MVC设计模式对代码分层,降低代码的耦合度
-------------------------------------------------
MVC是经典的设计模式,是代 码的分层思想
M:Model,即业务层,用来处理业务
V:View,视图层,用来展现数据
C:Controller,控制层,用来进行调度,是业务层和视图层的桥梁
其目的是要将代码解耦,便于团队开发及维护。
-------------------------------------------------
//转发:让继续完成这个请求
//1)将数据绑定到request上
req.setAttribute("emps", list);
//2)将请求提交给jsp让它继续处理,同时将处理请求的工具给jsp
//工具:request+response
//当前:/jsp2/findEmp
//目标:/jsp2/emp_list.jsp
req.getRequestDispatcher("emp_list.jsp").forward(req, res);
List<Emp> list=(List<Emp>)request.getAttribute("emps");
MVC下都是访问Servlet,访问jsp会没有数据(没有走Servlet)
三、转发和重定向
1、转发和重定向的相同点:
都是解决web组件之间的跳转问题
-WEB组件:Servlet/JSP
2、转发和重定向的区别(通俗的理解):小传奇 大传奇
3、转发和重定向的区别(专业的理解)(面试):
转发的特点:
1、一次请求
2、地址不变
3、一个请求只有一个request,A和B可以通过它共享数据
4、只能转发到项目内部的资源
重定向的特点:
1、二次请求
2、地址改变
3、二个请求只有二个request,A和B可以通过它共享数据
4、只能重定向到项目外部的资源
4、一般是这样
查询时用转发
增加、修改、删除后重定向到查询
依赖时用转发
不依赖时用重定向
归纳(面试题):
1、jsp有哪些内置对象?
2、什么是MVC?
3、转发和重定向的区别?
四、EL和JSTL
EL表达式:
<!-- 1.获取Bean属性 -->
<!-- request.getAttribute("stu").getName()-->
<p>姓名:${stu.name }</p>
<!-- request.getAttribute("stu").getAge)() -->
<p>年龄:${stu["age"] }</p>
<!-- request.getAttribute("stu").getCourse().getId() -->
<p>课程:${stu.course.id }</p>
<!-- EL的取值范围:
1.EL默认从如下4个对象中依次取值
page,request,session,application
这4个隐含对象是EL默认的取值范围
2.也可以指定取值范围
requestScope.stu.name
sessionScope.stu.name
3.设计默认取值的目的是为了开发者不用经常写范围,
是为了简化EL表达式-->
<p>性别:${requestScope.stu.sex }</p>
<!-- 2.支持运算 -->
<p>年龄+5:${stu.age+5 }</p>
<p>20-30间:${stu.age>20 &&stu.age<30 }</p>
<p>判空:${empty stu }</p>
<!-- 3.获取请求参数 -->
<p>参数:${param.user }</p>
-------------------------------------------
对象的属性
private Integer courseId;
Bean属性:
1.和get/set对应的属性叫Bean属性
//2.通过get/set反应出来的我们以为的属性叫Bean属性
//3.去掉get并将首字母小写的单词是Bean属性
//Bean属性通常都和对象属性一致,也可以修改为不一致
public Integer getId() {
return courseId;
}
----------------------------------------------
JSTL:
一个taglib引入一个标签
如何写自定义标签(理解)
-------------------
想给类传入一些数据的话,
可以调用方法时传入参数,(继承的父类方法中没有声明参数的话没法传)
可以实例化对象的时候通过构造器传入参数(这个类是由tomcat调用的,只会调用默认(无参)构造器)
可以通过set方法传参
一、项目简介
1、NETCTOSS
Net 网络 C:China 中国 T:Telecom 电信 O:Operation 运营 S:Support 支持 S:System 系统
中国电信运营支持系统-网络版
复制过来的html代码先看../路径问题
EL?获取请求参数
由于menu.jsp被其他所有jsp共用
因此无法预估目前是在哪个请求中调用它,所以此处适合写绝对路径
<%@include file="../menu.jsp" %>
用标签写
<c:import url="../menu.jsp"></c:import>
谁执行站在谁的角度看。
----------------------------------------
路径问题:谁执行站在谁的角度看。
1、浏览器访问服务器获得网页,然后加载网页时要获取图片是站在浏览器的角度来看网页和图片的相对关系
网页的路径是:/netctoss/findCost.do
图片的访问路径是:/netctoss/images/logo.png
相对路径是:images/logo.png
2、<c:import url="../menu.jsp"></c:import>
是在jsp翻译成jsp时执行,所以路径要站在服务器的角度上看两个jsp间的相对的关系
3、servlet转发到jsp时
当前:/netctoss/findCost.do
目标:/netctoss/WEB-INF/find.jsp
req.getRequestDispatcher("WEB-INF/find.jsp")
4、重定向到查询功能
当前:/netctoss/addCost.do
目标:/netctoss/findCost.do
res.sendRedirect("findCost.do");
5、网页跳转时
οnclick="location.href='/toUpdateCost.do?id=${c.costId}';"
6、各个页面的图标超链接
由于menu.jsp被其他所有jsp共用,因此无法预估目前是在哪个请求中调用它,所以此处适合写绝对路径
公用的文件一般写绝对路径
<li><a href="/netctoss/toIndex.do" class="index_on"></a></li>
7、异常
声明错误页面时需写绝对路径,但由于是转发过去,只能访问此项目内部的资源所以tomcat会自动的帮我们加上项目名,自己就别写项目名了
一、异常处理
都是tomcat调用的 异常往上抛都会抛给tomcat
将异常抛给容器,但底层的错误提示不要返回给用户
异常只允许抛service指定的异常,不能超出指定范围
配置错误页面
1.tomcat是所有服务端代码调用的入口,它在调用代码时会尝试捕获异常
2.默认的它捕获到异常时会自动转发到对应的错误页面,如404.html,500.html
3.我们可以通过配置改变这个默认的行为,明确告诉tomcat哪个异常去哪个错误页面这件事解决不了异常,仅仅是让用户看起来更友好而已
4.声明错误页面时需写绝对路径,但由于是转发过去,只能访问此项目内部的资源所以tomcat会自动的帮我们
加上项目名,自己就别写项目名了
<!-- 1.通过异常类型进行配置 -->
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/WEB-INF/error.jsp</location>
</error-page>
<!-- 2.通过异常编号(404/405/500)进行配置 -->
<error-page>
<error-code></error-code>
<location></location>
</error-page>
二、cookie和session(前面请求中存一份数据,后面要用这份数据)
1.业务场景(a,身份的识别 b,状态的保存和维护)
-登录时要记录账号
-以后访问查询、增加、修改页面时要显示账号
2、前提条件
-浏览器和服务器是多对一的关系
3、错误的做法
request:
-登录、查询是不同的请求,使用不同的request
config:
-假设开发项目时采用多个Servlet处理不同的请求
-登录有一个Servlet,查询有另一个Servlet
-多个Servlet用不同的config
-它没有读写变量的能力
context
-tomcat内只有一个对象
-每个人登录时传递的账号都是code="zhangsan" 的数据
-其中key都一样,存入context有冲突
4、正确的做法
使用cookie或session保存这样的数据
5、它们的区别
cookie存储在浏览器上,服务器压力小,但数据不安全
session存储在服务器上,服务器压力大,但数据安全
6、如何选择(*)
重要的数据存入seeion
一般的数据存入cookie
三、Cookie
1、使用:
保存: 检查通过后将账号存入cookie
//每个Cookie对象只能存一条数据,包括key和value,都是字符串
Cookie c1=new Cookie("code",code);
声明cookie的生存时间:
//>0时cookie保存在客户端的硬盘上
//=0时,cookie被浏览器删除
c1.setMaxAge(600000);
将Cookie发送给浏览器,浏览器接收到以后会自动保存
res.addCookie(c1);
存中文:
Cookie c2=new Cookie("city",java.net.URLEncoder.encode("北京","utf-8"));
获取:
out.println(c.getName()+":"+URLDecoder.decode(c.getValue(),"utf-8"));
获取:Cookie[] cs=req.getCookies();
2、特点(*)(跨请求跨Servet)
浏览器接收到cookie后会自动保存,浏览器再次访问服务器时会自动发送cookie
cookie保存在浏览器上,多个请求可以共用一组cookie,多个Servlet可以共用一组Cookie
每个用户(浏览器)访问服务器,都会获得一组cookie
3、cookie的路径问题
在/main/login路径下创建的cookie,它只对/main及下级路径有效
设置cookie的有效路径
c1.setPath("/jsp4");
4、要点
如何创建及发送cookie
如何获取/修改cookie
如何修改cookie的生存时间
如何向cookie存中文
如何修改cookie的生效路径
---------------------------------------------
数据存在数据库:数据永久保存,持久化数据
-----------------------------
5、cookie的限制
a,不安全,如果有敏感数据必须以cookie的方式
来保存,必须加密。
b,可以被用户禁止。
c,cookie只能保存少量的数据(4k)。
d,浏览器能够保存cookie的数量也有限制(大约300个左右)。
e,只能保存字符串。
EL默认的取值范围是:page->request->session->application
EL也可以从cookie中取值,语法为:cookie.key.value
四、session
1、演示案例
//存入session
//session是存储在服务器上的对象
//它的内部可以存储任意类型的数据
HttpSession session=req.getSession();
session.setAttribute("code", code);
//响应时服务器会自动创建cookie,将session的ID通过cookie发送给浏览器
//Cookie c=new Cookie("JSESSIONiD",session.getId())
//由于本次请求,浏览器传入了sessionId
//服务器就根据此SID找到那个旧的session,可以从中读取
//之前存的数据
HttpSession session=req.getSession();
String code=(String)session.getAttribute("code");
超时限制:
<session-config>
<session-timeout>1</session-timeout>
</session-config>
退出功能(销毁session)
session.invalidate();
2、特点(*)
浏览器第一次访问服务器时,服务器会给它创建一个session
(有jsp(翻译时就创建了,用不用都创建 )或者单独的Servlet用到session(不用不创建))
服务器会使用cookie将SID返回给浏览器,浏览器再次访 问服务器时会传入SID
多个请求可以共用同一个session
多个Servlet可以共用同一个session
服务器会给每个浏览器创建1个session
cookie被禁用,session不能用,可以URL重写(不用管)
验证码功能:
//生成验证码及图片
Object[] o=ImageUtil.createImage();
//将验证码存入session
HttpSession session=req.getSession();
session.setAttribute("imgCode", o[0]);
//将图片输出给浏览器
res.setContentType("image/png");
//获取输出流,该流由服务器自动创建
//它所输出的目标就是当前访问的页面
OutputStream os=res.getOutputStream();
BufferedImage image=(BufferedImage) o[1];
ImageIO.write(image, "png", os);
os.close();
img src="createImg.do" οnclick="this.setAttribute('src','createImg.do?x='+Math.random());"
修改图片属性,路径后面增加了参参数(随机数) 是为了欺骗浏览器,让它以为路径变了
--先检查验证码,这样如果验证码错了就不用访问一次数据库来验证账号密码了
if(ycode==null&&!ycode.equalsIgnoreCase(imgcode)){
req.setAttribute("error", "验证码错误");
req.getRequestDispatcher("WEB-INF/login.jsp").forward(req, res);;
return;//后面还有内容,要return结束方法
}
---------------------------------
遇到错误:
打桩,排除
不存在,看方法名,可能某些代码语法被破坏,二分法
配置文件的错误,排除法
-----------------------------------------------
二、cookie和session的作用‘
1、通俗的描述(理解)
它们内部存储的数据满足如下规则:
这些数据在不同的请求中可以共用
这些数据在不同的Servlet之间可以共用
每个浏览器都有一组这样的数据
2、专业的描述(背)
HTTP协议是无状态协议,就是服务器没有记住浏览器
cookie和session就是用来管理状态,让服务器记住浏览器
状态:浏览器曾经访问过服务器的证据(数据)
- 过滤器
servlet规范当中定义的一种特殊的组件,用来拦截容器的调用过程并进行处理。
1、过滤器的作用
用来处理项目中的公共的需求
举例:记录日志,过滤敏感词,权限检查
公共的需求:很多请求都包含的业务
2、过滤器的开发步骤
创建一个类,实现过滤器接口Filter ---> 在web.xml里配置这个类 ----> 过滤器由服务器自动调用
3、过滤器优先级
当有多个过滤器都满足过滤的条件,则容器依据<filter-mapping>的先后顺序来调用。
4、初始化参数
step1,在web.xml文件当中,配置初始化参数
<init-param>
<param-name>size</param-name>
<param-value>5</param-value>
</init-param>
step2,使用
String FilterConfig.getInitParameter(String
paramName) ;
5、过滤器的优点
a,在不修改程序源代码的基础上,增加一些功能。
b, 可以将多个组件相同的处理逻辑集中写在过滤器里面,方便代码的维护
filter:
1、init()
tomcat启动时会自动实例化Filter,然后调用其init()来初始化Filter,调用此方法时会传入config,该对象和Filter是1
对1的关系,可以给Filter预置参数(web.html)该对象和ServletConfig用法完全一样
2、doFilter()
方法是处理公共业务的方法,Filter相当于是Servlet们的管家,tomcat在调用Servlet之前会将请求提交给Filer,
Filter有权让请求继续,也有权让请求终止
tomcat就是调用doFilter方法来让Filter统一处理请求的,调用前它会创建好request和reponse并传入,创建的类型:
RequestFacade和ResponseFacade
请求继续,向下执行 chain.doFilter(req, res);
3、destroy()
关闭tomcat时自动调用此方法
-------------------------------------
定义为成员变量,把方法中得到的值赋值给成员变量,在其他方法中就可以用了
多态掌握不好?
不需要继续记得return
//有3个请求不需要过滤,排除它们
String[] paths=new String[]{"/toLogin.do",
"/login.do","/createImg.do"};
//当前路径
String sp=request.getServletPath();
for(String p:paths){
if(p.equals(sp)){
//不必过滤,请求继续执行
chain.doFilter(request, response);
return;
}
}
------------------------------------------
四、listener
request和response在请求之初创建,在响应后销毁
什么是监听器
servlet规范当中定义的一种组件,用来监听servlet容器产生的事件并进行处理。
注:主要有两大类事件:
a,生命周期相关的事件:容器创建或者销毁了request,session,ServletContext(servlet上下文)产生的事件。
b,绑订数据相关的事件: 执行了request,session,servlet上下文的setAttribute,removeAttribute产生的事件。
(2)如何写一个监听器
step1,写一个java类,依据要监听的事件类型实现相应的监听器接口。比如,要监听session对象的创建和销毁,可以实现HttpSessionListener接口。
step2,在监听器接口方法中,实现相应的监听处理逻辑:
比如,要统计在线人数,可以在session对象
创建时,将人数加1,session对象销毁时,将人数减1。
step3,注册(web.xml)
(3)ServletContext(servlet上下文)
1)servlet上下文是什么?容器在启动之后,会为每一个web应用创建唯一的一个符合ServletContext接口要求的对象,该对象会一直存在,除非应用被卸载或者容器被关闭。
2)如何获得Servlet上下文
GenericServlet,ServletConfig, FilterConfig,HttpSession都提供了getServletContext方法。
3)作用
a, 绑订数据
setAttribute,getAttribute,removeAttribute
注:
request,session,servlet上下文都提供了绑订数据相关的三个方法,区别如下:
区别1:绑订数据的生存时间不一样,request <session < servletContext。
区别2:可以访问的范围不一样,request绑订的数据只有同一个请求所涉及的组件(转发) 可以访问,session绑订的数据只有同一个会话所涉及的组件可以访问,servlet上下文绑订的数据整个应用的所有组件均可以访问。
b,访问全局的初始化参数 所谓全局的初始化参数,指的是该参数可以被web.xml文件中配置的所有组件访问。
step1,
<context-param>
<param-name>company</param-name>
<param-value>IBM</param-value>
</context-param>
step2,
ServletContext.getInitParameter(
String paramName);
要统计在线人数
1,servlet线程安全问题
(1)为什么说servlet会有线程安全问题
a,servlet容器收到请求之后,会启动一个线程
来处理请求。
b,在默认情况下,servlet容器只会创建一个
servlet实例。
这样,当有多个线程同时访问某个servlet时,就
有可能发生线程安全问题,比如,这些线程同时去
修改servlet的属性时。
(2)如何解决
1)加锁
synchronized
2)让servlet实现SingleThreadModel接口(
不建议使用)。
容器会为实现了该接口的servlet创建多个
实例(一个线程分配一个)。
因为有可能会创建过多的实例(对象),所以
建议少用。
servlet小结
1,servlet基础
(1)什么是servlet?
(2)如何开发一个servlet?
(3)什么是servlet容器?
(4)http协议(什么是http协议,请求/响应数据包的结构,
两种请求方式,状态码,消息头)。
(5)servlet是如何运行的?
2,servlet核心
(1)如何获得请求参数值
String request.getParameter(String paramName);
String[] request.getParameterValues(String paramName);
(2)表单有中文参数,如何处理
step1,要保证表单所在的页面按照指定的字符集打开。
step2,服务器端按照对应的字符集去解码。
request.setCharacterEncoding(String charset);
(3)servlet如何输出中文
response.setContentType("text/html;charset=utf-8");
注:指定支持中文的字符集。
(4)servlet容器如何处理请求资源路径
(5)如何让一个servlet处理多种请求。
String request.getRequestURI();
(6)重定向与转发
response.sendRedirect(String url);
request.setAttribute(String name,Object obj);
RequestDispatcher rd = request.getRequestDispatcher(String uri);
rd.forward(req,res)
(7)servlet的生命周期
(8)ServletContext
(9)servlet线程安全问题
3,状态管理
(1)什么是状态管理
(2)如何进行状态管理
(3)cookie
Cookie c = new Cookie(String name,String value);
URLEncoder.encode
URLDecoder.decode
c.setMaxAge(int seconds);
c.setPath(String path);
response.addCookie(c);
Cookie[] request.getCookies();
cookie.getName();
cookie.getValue();
(4)session
HttpSession session = request.getSession(boolean flag);
HttpSession session = request.getSession();
setAttribute,getAttribute,removeAttribute
session.setMaxInactiveInterval(int seconds);
session.invalidate();
response.encodeURL(String uri);
response.encodeRedirectURL(String url);
4,数据库访问
5,过滤器与监听器
6,典型案例
员工信息管理
登录和session验证
验证码
jsp
1,什么是jsp?
2,如何写一个jsp?
step1,写一个以.jsp为后缀的文件
step2,添加如下内容:
(1)html 直接写
(2)java代码
1)java代码片断 <% java语句; %>
2)jsp表达式 <%= java表达式%>
3)jsp声明 (a1.jsp) <%! 变量或者方法 %>
(3)隐含对象
1)什么是隐含对象
2)为什么可以直接使用这些隐含对象
3)有哪一些隐含对象
容器会为每一个jsp实例(jsp对应的那个servlet对象)创建唯一的一个符合PageContext
接口要求的对象,该对象就是pageContext。该对象会一直存在,除非jsp实例被销毁。
作用1:绑订数据 (a2.jsp,a3.jsp)setAttribute getAttribute removeAttribute
注:pageContext上绑订的数据只有对应的jsp实例能访问。
作用2:获得其它八个隐含对象。
pageContext提供了查找其它所有隐含对象的方法。
b)exception (a4.jsp,a5.jsp)
当page指令的isErrorPage属性设置为true时,才能使用该隐含对象。该隐含 对象提供了一些方法,用来获得jsp在运行时产生的一些异常信息。
c)config (a6.jsp) ServletConfig,可以用来访问jsp的初始化参数。
d)pagejsp实例本身。
4)指令
a,什么是指令?
通知容器,在将jsp转换成servlet类时,做一些额外的处理,比如导包。
b,有哪些指令
Page import pageEncoding contentType errorPage:指定一个错误处理页面,当当前 页面发生异常之后,容器会调用该错误处理页面。
isErrorPage:true/false(缺省),当值为true时,可以使用exception隐含对象。 session (a7.jsp):true(缺省)/false,当值为false, 容器不再添加获得session对象的代码 。
Include
file:告诉容器,将file属性指定的文件的 内容添加到该指令所在的位置。
taglib导入jsp标签。
5)注释 (a8.jsp)
a,<!-- 注释的内容 -->
b,<%--注释的内容 --%>
区别:第一种方式,注释的内容如果是java代码,会执行。
3,jsp是如何执行的?
step1,容器要将jsp文件转换成servlet
1)html -------->service方法 out.write
2) <% %> ------>service方法 照搬。
3) <%= %> ------>service方法 out.print
4) <%! %> ------>给servlet添加新的属性或者方法。
step2,容器调用该servlet
jsp标签和el表达式
(1)jsp标签是什么?
jsp标签其实就是一个占位符,对应一个标签类,容器遇到jsp标签之后,会找到对应的标签中的代码然后执行。因为在jsp文件里面直接写java代码,不利于jsp文件的维护(比如,将带有java代码的jsp文件交给美工去修改就很不方便),所以,sun才制订了jsp标签技术规范。
jsp标签的语法类似于普通的html标签(有标签体, 有属性),使用jsp标签之后,jsp文件会变得简洁,利于维护,利于代码的复用。
(2)el表达式
一套简单的计算规则,用于给jsp标签的属性赋值,现在,也可以直接输出。
(3)el表达式的使用
1)访问bean的属性
a)方式一 (a1.jsp)
${user.name}:容器会依次从pageContext,request,
session,application中查找绑订名称为"user"的对象,接下来,调用该对象的getName方法,最后输出。
注:如果依据绑订名找不到对应的对象,会输出空字符串。
对于null,会转化成空字符串输出。如果要指定查找范围,可以使用
pageScope,requestScope,sessionScope,applicationScope即可。
b)方式二 (a1.jsp)
${user["name"]}
注:这种方式允许[]里面出现变量。允许[]里面出现从0开始的下标,用来访问数组中的某个元素。
练习:(a2.jsp)
使用el表达式输出Employee对象的各个属性。
Employee(name,salary,age)。
2)做一些简单的计算,计算的结果可以直接输出,
也可以用来给jsp标签的属性赋值 (a3.jsp)。
a,算术运算: "+","-","*","/","%"。
b,关系运算: ">",">=","<","<=","==","!="。
c,逻辑运算:"&&","||","!"
d,empty运算: 用来判断集合是否为空,或者是
否是一个空字符串。
3)获取请求参数值 (a4.jsp)
${param.name} 等价于request.getParameter("name");
${paramValues.city} 等价于request.getParameterValues("city");
(4)jstl标签
1)jstl是什么(java standard tag lib)
apache开发的一套标签,后来捐献给了sun,sun 将其命名为jstl。在javaee5.0当中,已经包含了该标签。
2)如何使用jstl?
step1,将jstl相关的jar文件拷贝到WEB-INF\lib下。
注:如果使用的是javaee5.0或者以上版本,不用拷贝了。
step2,使用taglib指令引入要使用的标签。
3)jstl核心标签
a) if标签 (a5.jsp)
<c:if test="">标签体</c:if>
当test属性值为true时,容器会执行标签体的内容。test属性可以使用el表达式来赋值。 a) if标签 (a1.jsp)
<c:if test="" var="s" scope="page">标签体</c:if>
当test属性值为true时,容器会执行标签体的内容。
test属性可以使用el表达式来赋值。 var属性:指定一个绑订名称。
scope属性:指定绑订范围("page","request","session","application")。
b)choose标签 (a2.jsp)
<c:choose>
<c:when test="">
</c:when>
<c:otherwise>
</c:otherwise>
</c:choose>
when标签可以出现1次或者多次,otherwise可以出现0次或者1次,表示例外。
当test属性值为true时,执行标签体的内容,test属性可以使用el表达式。
c) forEach标签 (a3.jsp)
用来遍历一个集合或者数组。
<c:forEach var="" items="" varStatus="">
</c:forEach>
items属性:用来指定要遍历的集合或者数组,可以使用el表达式。
var属性:指定一个绑订名称。
注:绑订范围是pageContext,容器每一次从集合或者数组中取一个元素,然后将该元素绑订到pageContext对象上。
varStatus属性:指定一个绑订名称。
注: 绑订范围是pageContext,绑订值是一个由容器创建的特殊的对象,该对象封装了当前遍历的状态,比如,该对象提供了
getIndex(): 当前正在被遍历的元素的下标(从0开始)。
getCount():当前是第几次迭代。
练习:
将员工列表(empList.jsp)中的java代码除掉(
使用jsp标签和el表达式来替换)。
参考a3.jsp
1,自定义标签
step1,写一个java类,继承SimpleTagSupport类。
step2,在doTag方法里面,编写处理逻辑。
step3,在.tld文件当中,描述标签。
注:.tld文件要放到WEB-INF下。
<body-content>empty</body-content>
<body-content>scriptless</body-content>
<body-content>JSP</body-content>
empty: 该标签没有标签体。
scriptless:该标签可以有标签体,但是,标签体的内容不能够出现java代码。
<% %>,<%= %>,<%! %>
JSP:该标签有标签体,并且,标签体的内容可以是java代码。但是,只有复杂标签技术支持该值,简单标签技术只支持empty和scriptless。