|
一、ServletContext(非常重要)
1、作用:每一个JavaWeb应用都会有唯一的ServletContext对象。
在Tomcat加载应用时,就创建该对象的实例。(ServletContext是一个接口,它的实例类由服务器提供)
实现servlet之间数据共享
public
class ServletContextDemo1Servlet
extends HttpServlet {
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletConfig config
= getServletConfig();
//只为当前 Servlet 服务
ServletContext sc
= config.getServletContext();
sc.setAttribute(
"p" ,
"ppp" ); }
public
class ServletContextDemo2Servlet
extends HttpServlet {
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//只为当前 Servlet 服务
ServletConfig config
= getServletConfig();
//只要是当前应用,不论是谁,得到的ServletContext都是同一个对象
ServletContext sc
= config.getServletContext();
Object obj
= sc.getAttribute(
"p" ); }
2、得到ServletContext的实例:
ServletConfig getServletContext()
public
void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//获取当前服务的 config ,只为当前 Servlet 服务
ServletConfig config
= getServletConfig();
//获取ServletContext对象,就可以对ServletContext进行操作了.
//只要是当前应用,不论是谁,得到的ServletContext都是同一个对象
//就是说ServletContext的范围比 Servlet 还要大
ServletContext sc
= config.getServletContext();
// 此句是另一个 Servlet 上设置数据sc.setAttribute("q"," qqq ");
//读取并打印数据
resp.getOutputStream().write(((String)sc.getAttribute(
"q" )).getBytes());
//如果先运行Demo2,则会报错,空指针异常,必须先向ServletContext存值,才可以取出 }
3、读取应用级的参数
web.xml中:
<context-param>
<!-- 配置的是应用全局参数,读取应该使用ServletContext -->
<param-name>
encoding</param-name>
<param-value>
UTF-8</param-value>
</context-param>
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//实际开发需要删掉this.因为这是多余的.在这里写出来是为了明确HttpServlet里面有这个方法
ServletContext sc
=
this .getServletContext();
//读取对象,打印到控制台上
String str
= sc.getInitParameter(
"encoding" );
System. out .println(str); }
4、实现Servlet的转发。
public
class ServletContextDemo4Servlet
extends HttpServlet {
//演示转发:ServletContext转发的。源,转发到Demo5,最后显示的是Demo5的信息
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.getOutputStream().write(
"I am 4" .getBytes());
ServletContext sc
= getServletContext();
//请求分发器 path,目标路径,该路径必须以"/"开头。斜线代表的是当前应用/day04_00_servletContext
RequestDispatcher rd
= sc.getRequestDispatcher(
"/servlet/ServletContextDemo5Servlet" );
//必须forward一下,否则不会转发
rd.forward(request, response); }
5、读取配置文件(*.properties *.xml)
方式一:利用ServletContext
特点:用于Web环境下。可以读取应用任何目录下的任何文件
//利用ServletContext读取cfg3.properties
private
void test3(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String realPath
= getServletContext().getRealPath(
"/WEB-INF/classes/com/itheima/servlet/cfg3.properties" );
//创建Properties类来读取文件内容。
Properties props
=
new Properties();
//用FileInputStream流来关联 。
props.load(
new FileInputStream (realPath));
String value
= props.getProperty(
"hello" );
response.getOutputStream().write(value.getBytes());
}
//利用ServletContext读取cfg2.properties
private
void test2(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String realPath
= getServletContext().getRealPath(
"/WEB-INF/classes/cfg2.properties" );
Properties props
=
new Properties();
props.load(
new FileInputStream(realPath));
String value
= props.getProperty(
"hello" );
response.getOutputStream().write(value.getBytes());
}
//利用ServletContext读取cfg1.properties
private
void test1(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String realPath
= getServletContext().getRealPath(
"/WEB-INF/cfg1.properties" );
Properties props
=
new Properties();
props.load(
new FileInputStream(realPath));
String value
= props.getProperty(
"hello" );
response.getOutputStream().write(value.getBytes()); }
方式二:利用ResourceBundle
特点:可以用在非web环境和Web环境下。专门读取properties文件的,只能读取类路径中的properties文件
//利用ResourceBundle(国际化)读取cfg3.properties
private
void test5(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//注意使用的是基名
ResourceBundle rb
= ResourceBundle. getBundle (
"com.itheima.servlet.cfg3" );
response.getOutputStream().write(rb.getString(
"hello" ).getBytes());
}
//利用ResourceBundle(国际化)读取cfg2.properties
private
void test4(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ResourceBundle rb
= ResourceBundle. getBundle (
"cfg2" );
//基名
response.getOutputStream().write(rb.getString(
"hello" ).getBytes()); }
方式三:利用类加载器(更加专业)
特点:可以用在非web环境和Web环境下,可以读取类路径中的任何配置文件,不适合读取特别大的文件
//利用类加载器读取cfg3.properties的真实路径
private
void test8(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获得类加载器,用类加载器获得指定资源路径
ClassLoader cl
= ServletContextDemo7Servlet.
class .getClassLoader();
URL url
= cl.getResource(
"com/itheima/servlet/cfg3.properties" );
//得到真实的绝对路径。如果该路径有空格或有中文,构建流时报错
String realPath
= url.getPath();
InputStream in
=
new FileInputStream(realPath);
Properties props
=
new Properties();
props.load(in);
String value
= props.getProperty(
"hello" );
response.getOutputStream().write(value.getBytes());
}
//利用类加载器读取cfg3.properties,注意资源路径
private
void test7(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获得类加载器,再用类加载器获得指定资源的输入流
ClassLoader cl
= ServletContextDemo7Servlet.
class .getClassLoader();
InputStream in
= cl.getResourceAsStream(
"com/itheima/servlet/cfg3.properties" );
Properties props
=
new Properties();
props.load(in);
String value
= props.getProperty(
"hello" );
response.getOutputStream().write(value.getBytes());
}
//利用类加载器读取cfg2.properties,注意资源路径
private
void test6(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ClassLoader cl
= ServletContextDemo7Servlet.
class .getClassLoader();
InputStream in
= cl.getResourceAsStream(
"cfg2.properties" );
Properties props
=
new Properties();
props.load(in);
String value
= props.getProperty(
"hello" );
response.getOutputStream().write(value.getBytes()); }
二、Servlet规范中的核心接口类图(非常重要)
javax.servlet.Servlet
javax.servlet.GenericServlet
javax.servlet.http.HttpServlet
javax.servlet.ServletContext
javax.servlet.RequestDispatcher
javax.servlet.ServletConfig
javax.servlet.ServletRequest
javax.servlet.ServletResponse
三、响应对象HttpServletResponse(非常重要)
1、输出数据中文编码
//利用字节流输出中文数据
private
void test3(HttpServletResponse response)
throws IOException {
int data
=
97;
ServletOutputStream out
= response.getOutputStream();
//如果不加转成字符串,会输出a
out.write((data
+
"" ).getBytes());
}
private
void test2(HttpServletResponse response)
throws IOException {
String data
=
"陈冠希爱阿娇" ;
ServletOutputStream out
= response.getOutputStream();
//通知浏览器,服务端使用的编码
response.setContentType(
"text/html;charset=UTF-8" );
//记住
byte b[]
= data.getBytes(
"UTF-8" );
out.write(b);
}
//用本地平台默认编码输出:没有乱码
private
void test1(HttpServletResponse response)
throws IOException {
String data
=
"中国" ;
ServletOutputStream out
= response.getOutputStream();
byte b[]
= data.getBytes();
out.write(b);
}
//日后使用
private
void test1(HttpServletResponse response)
throws IOException {
String data
=
"李宗瑞李宗盛" ;
//更改字符流默认查询的码表 只对post提交有效
response.setCharacterEncoding(
"UTF-8" );
//通知浏览器解码用什么编码
response.setContentType(
"text/html;charset=UTF-8" );
PrintWriter out
= response.getWriter();
out.write(data);
//默认查ISO-8859-1 规范要求 }
2、一些应用案例(响应头的应用)
下载中文文件名的文件
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到输入流:路径该怎么获取,斜线就代表当前应用
String path
=
"/WEB-INF/阿娇.jpg" ;
//截取文件名,包含头,所以要+1,把/排出
String filename
= path.substring(path.lastIndexOf(
"/" )
+
1);
//告知客户端以下载的方式打开
response.setHeader(
"Content-Disposition" ,
"attachment;filename="
+URLEncoder. encode (filename,
"UTF-8" ));
response.setHeader(
"Content-Type" ,
"application/octet-stream" );
//根据相对于当前应用的路径,得到绝对路径
String realPath
= getServletContext().getRealPath(path);
//下面打印:C:\ apache - tomcat -6.0.35\ webapps \day04_01_response\WEB-INF\阿娇. jpg
System. out .println(realPath);
InputStream in
=
new FileInputStream(realPath);
OutputStream out
= response.getOutputStream();
int len
=
-
1;
byte b[]
=
new
byte [
1024];
while ((len
=in.read(b))
!=
-
1){
out.write(b,
0, len);
}
in.close();
out.close(); }
输出CAPTCHA图像,就是验证图片
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//通知浏览器,图片不要缓存
response.setHeader(
"Expires" ,
"-1" );
response.setHeader(
"Cache-Control" ,
"no-cache" );
response.setHeader(
"Pragma" ,
"no-cache" );
int width
=
120;
int height
=
25;
//搞出代表内存图片的对象BufferedImage,然后取画笔:开始画
BufferedImage image
=
new BufferedImage(width,height,BufferedImage. TYPE_INT_RGB );
Graphics g
= image.getGraphics();
//填充背景
g.setColor(Color. YELLOW );
g.fillRect(
0,
0, width, height);
//画边框
g.setColor(Color. BLUE );
g.drawRect(
1,
1, width
-
2, height
-
2);
//画干扰线
g.setColor(Color. GRAY );
Random r
=
new Random();
for (
int i
=
0;i
<
30;i
++)
g.drawLine(r.nextInt(width), r.nextInt(height), r.nextInt(width), r.nextInt(height));
//写随机验证码
g.setColor(Color. RED );
g.setFont(
new Font(
"宋体" ,Font. BOLD
|Font. ITALIC ,
18));
//数字
// for( int i=1;i<5;i++){
// g.drawString(r.nextInt(10)+"", x*22, 20);
// x+=20;
// }
// 汉字的,随意添加即可
String base
=
"\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728" ;
int x
=
22;
for (
int i
=
1;i
<
5;i
++){
g.drawString(base.charAt(r.nextInt(base.length()))
+
"" , x
*
22,
20);
x
+=
20;
}
//输出到页面上:ImageIO
ImageIO. write (image,
"jpg" , response.getOutputStream()); }
//定时刷新到别处
private
void test2(HttpServletResponse response)
throws IOException {
response.setContentType(
"text/html;charset=UTF-8" );
response.setHeader(
"Refresh" ,
"2;url=http://www.itheima.com" );
response.getWriter().write(
"注册成功!2秒后自动转向主页" );
}
//定时2秒就刷新自己
private
void test1(HttpServletResponse response)
throws IOException {
response.setIntHeader(
"Refresh" ,
2); }
控制缓存的有效期
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//相对于当前时间的。如果值比当前时间的毫秒值小,倒退1小时。
response.setDateHeader(
"Expires" , System. currentTimeMillis ()
+
1
*
60
*
60
*
1000); }
3、一些细节
a,字节流和字符流不能同时使用
b,服务器会自动关闭流
c,Servlet向ServletOutputStream或PrintWriter对象中写入的数据,将被Tomcat从response里面获取,Tomcat将这些数据当作响应消息的正文,
四、请求对象HttpServletRequest(非常重要)
1、常用方法
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//打印客户端的 url 地址
String url
= request.getRequestURL().toString();
//打印客户端的 uri 地址
String uri
= request.getRequestURI();
//打印客户端的GET返回值
String queryString
= request.getQueryString();
//打印客户端的访问IP地址
String remoteAddr
= request.getRemoteAddr();
//打印客户端的访问port
int remotePort
= request.getRemotePort();
//打印客户端的提交数据方式
String method
= request.getMethod(); }
2、获取请求消息头
public
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System. out .println(
"----------------" );
//获取所有的请求消息头和值
Enumeration e
= request.getHeaderNames();
//用while循环.这个类的方法不多,hasMoreElements判断里面是否还有
while (e.hasMoreElements()){
String headerName
= (String)e.nextElement();
System. out .println(headerName
+
":::::"
+request.getHeader(headerName));
}
}
3、获取请求参数
//获取所有的请求参数值
private
void test4(HttpServletRequest request, PrintWriter out) {
//key: String请求参数名字 value:String[] 请求参数值
Map
<String,String[]
> map
= request.getParameterMap() ;
for (Map.Entry
<String, String[]
> me
:map.entrySet()){
System. out .println(me.getKey()
+
"="
+Arrays. asList (me.getValue()));
}
}
//获取所有的请求参数值
private
void test3(HttpServletRequest request, PrintWriter out) {
Enumeration e
= request.getParameterNames();
//所有的请求参数名
while (e.hasMoreElements()){
String paramName
= (String)e.nextElement();
System. out .println( paramName
+
"="
+Arrays. asList (request.getParameterValues( paramName )));
}
}
//获取重名的请求参数值
private
void test2(HttpServletRequest request, PrintWriter out) {
//同样的key可能会有多个value,所以取回的value是数组
String[] passwords
= request.getParameterValues(
"password" );
}
//获取单一的请求参数值
private
void test1(HttpServletRequest request, PrintWriter out) {
//用户所有的界面输入都是String类型,如果表单的输入域没有name属性,浏览器根本不传递数据
String username
= request.getParameter(
"username" );
//
String password
= request.getParameter(
"password" ); }
4、常用表单及数据的获取
//**封装数据到JavaBean中:遵循了一个约定,表单字段名和User中的属性(getter setter)一致
private
void test10(HttpServletRequest request, PrintWriter out) {
try {
User user
=
new User();
System. out .println(
"封装前:"
+user);
//String-->基本类型:自动转换。
//日期的不会:注册类型转换器
// ConvertUtils.register(new Converter() {
// public Object convert(Class type, Object value) {
// DateFormat df = new SimpleDateFormat(" yyyy -MM- dd ");
// if(type==Date.class){
// //要把String转成Date
// String s = (String)value;
// try {
// return df.parse(s);
// } catch (ParseException e) {
// throw new RuntimeException(e);
// }
// }else if(type==String.class){
// //把Date转成String
// Date date = (Date)value;
// return df.format(date);
// }
// return null;
// }
// }, Date.class);
ConvertUtils. register (
new DateLocaleConverter(), Date.
class );
//请看上面注释
BeanUtils. populate (user, request.getParameterMap());
//原理看test7
System. out .println(
"封装后:"
+user);
}
catch (Exception e) {
e.printStackTrace();
}
}
//**封装数据到JavaBean中:遵循了一个约定,表单字段名和User中的属性(getter setter)一致
private
void test8(HttpServletRequest request, PrintWriter out) {
try {
User user
=
new User();
System. out .println(
"封装前:"
+user);
BeanUtils. populate (user, request.getParameterMap());
//原理看test7
System. out .println(
"封装后:"
+user);
}
catch (Exception e) {
e.printStackTrace();
} }
(反射及内省)
//封装数据到JavaBean中:遵循了一个约定,表单字段名和User中的属性(getter setter)一致
private
void test6(HttpServletRequest request, PrintWriter out) {
try {
Map
<String, String[]
> map
= request.getParameterMap() ;
User user
=
new User();
System. out .println(
"封装前:"
+user);
//封装
for (Map.Entry
<String, String[]
> me
:map.entrySet()){
String paramName
= me.getKey();
//请求参数名 和User中的属性(getter setter)一致
String[] paramValue
= me.getValue();
//请求参数值
//属性描述其
PropertyDescriptor pd
=
new PropertyDescriptor(paramName, User.
class );
//调用其中的setter方法
Method method
= pd.getWriteMethod();
if (paramValue
!= null
&mValue. length
>
1){
//看如何反射main方法
method.invoke(user, (Object)paramValue);
}
else {
method.invoke(user,paramValue) ;
}
}
System. out .println(
"封装后:"
+user);
}
catch (Exception e) {
e.printStackTrace();
} }
以流的形式获取请求正文内容
private
void test9(HttpServletRequest request, PrintWriter out)
throws IOException {
ServletInputStream in
= request.getInputStream();
int len
=
-
1;
byte b[]
=
new
byte [
1024];
while ((len
=in.read(b))
!=
-
1){
System. out .println(
new String(b,
0,len));
}
in.close(); }
5、请求转发和重定向
6、请求范围的域对象
|