WEB基础之Request和Response

/*
动态网页开发技术主要有:jsp/servlet、asp、php三种方式
jsp是其实就是servlet。学会了servlet,就懂了jsp。


servlet的生命周期:
客户端第一次访问服务器时,在内存中加载servlet的编译文件,生成一个servlet对象,创建之后
驻留在内存中,等待其他的请求。
一旦被创建,init会执行,每次请求会执行service方法。
当关闭服务器或者应用被删除时,servlet会被摧毁,摧毁的时候调用destroy方法。






熟悉,学会读rose画的时序图。


写Servlet要实现Servlet接口,而java工程师为了让程序员更好的开发程序,帮着实现了两个类:
GenericServlet、HttpServlet两个类。
实际的开发中,继承HttpServlet类就可以了,比较方便






Servlet的线程安全问题
在服务器调用service方法时,并且并发请求时,若可能会引发线程安全问题。
1)可以用同步代码块的问题的角度来解决此问题,但是考虑到实际应用的情况,很多人
并发访问同一个web资源,会造成等待的问题,体验有所下降。
2)Servlet解决此问题的方法就是实现SingleThreadMode接口,用以标记线程安全的。
SingleThreadMode啥都没有定义,被称为标记接口.用以标记Servlet是线程安全的.
很多类似的解决问题的方法,如Serialable接口,用以标记对象序列化.
该类解决方法还是有些问题,2.4版本已经不建议使用,开发中常用第一种方式。








服务器调用Servlet的时候会传递的一些参数:
1、ServletConfig对象:用以封装Servlet的配置信息
在web.xml中配置上:
<init-param>
<param-name>data</param-name>
<param-value>value</param-value>
</init-param>
服务器就自动的封装成ServletConfig对象传给Servlet对象,在servlet中调用
this.getServletConfig()方法。


开发过程中:什么数据才通过ServletConfig配置呢。
比如:1)最终需要使用哪种码表进行输出,就可以在配置数据中进行配置.
2)初始化信息有时候读取哪个配置文件,也可以通过配的方式来配置给servlet.
总之,可能变化的信息,不适合在程序中进行固定的一些数据就可以通过配置的方式
来进行配置完成,配给servlet,通过getServletConfig()这种方式来进行获取,比较实用且方便.


2、ServletContext对象:表示当前web应用.拥有一些管理web引用的方法,另外还有其他一些方法。
维护了ServletContext对象的引用.
ServletContext的声明周期:服务器启动的时候就为每个web应用创建一个ServletContext;当停止服务器
或者删除web应用时,web应用的ServletContext会被销毁.


如何获取ServletContext:
1)ServletContext context = this.getServletConfig().getServletContext();
2)this.getServletContext();
一个web应用中所有的Serlet共享一个ServletContext对象,所以多个Servlet通过ServletContext
对象实现数据共享。(ServletContext对象通常被称之为Contex域对象。)
另外还有request域,page域,session域。
ServletContext域是整个web应用,即范围最大,整个web应用共享ServletContext中的数据.
域在中文的意思即范围的意思,就是个容器。


实际使用例子:在web.xml中作如下配置:
<context-param>
<param-name>data</param-name>
<param-value>value</param-value>
</context-param>


实际开发中的应用场景:
1、所有的servlet都连接一个数据库的配置.
2、用ServletContext实现请求转发。你找我借钱,我帮你去找别人。一次请求。开发过程中用处超级多。
RequestDispatcher rd = this.getServletContext().getRsquest("1/jsp");
rd.forward(resquest,response);//转发
但是实际开发过程中,不能带数据,如果带实际的数据会造成线程安全问题。应该通过
request域带数据.
  重定向:你找我借钱,我让你去找别人。两次请求。


web应用中常用作配置文件的两种文件,properti和xml文件:
properties配置文件:如果配置文件中的数据没有关系,就用properties文件作为配置文件.
例如:通过properties文件读取连接数据库的相关数据
下面一段代码背过:
1)InputStream in = this.getServletContext().getResultAsString("/WEB-INF/classes/db.properties");

Properties pro = new Properties();
pro.load(in);//读取该文件


String url = prp.getProperty("url");
读取资源文件需要注意的地方:
FileInputStream in = new FileInputStream("src/db.properties");//这里不对,没有src路径
FileInputStream in = new FileInputStream("classes/db.properties");//这里也不对,这是相对路径
//相对路径指的是相对java虚拟机的目录,因为是服务器启动的java虚拟机,所以就是相对于
服务器的startup.bat所在路径。所以也不对。太麻烦了。。。死活也不用。
Properties prop = new Properties();
...
2)通过ServletContext的getRealPath();获取到资源的绝对路径之后再获取各个参数。
String path = this.getServletContext().getRealPath("/WEB-INF/classes/db.properties");
FileInputStream fil = new FileInputStream(path);
..下面依次取出。


xml配置文件:如果配置文件中的数据有关系,就用xml文件作为配置文件.




3)如果读取资源文件的类不是Servlet的话,就要用类装载器来实现。比如Servlet中调用dao
层进行数据的操作。其实就是用反射的思想
具体实现如下:
InputStream in = UserDao.class.getClassLoader().getResourceAsStream("db.properties");
Properties prop = new Properties();
prop.load(in);






request、response




response:
1、设置编码格式
2、
3、下载资源






文件下载:从servlet里面读取资源,就用ServletContext来实现。


两种具体选择方式:
1、把资源作为流访问
2、得到文件的路径


下载要用到文件名,所以要得到文件的绝对路径这个方法。


具体代码:
String path = this.getServletContext().getRealPath("/download/1.jpg");
String fileName = path.substring(path.lastindexOf("\\")+1);


response.setHeader("content-disposition","attachement,filename"+filaName);


..一顿狂读。。
最后别忘了关闭资源



注意:如果下载文件含中文,则文件名需要通过设置编码格式才能解决中文文件的下载问题。


response另一个重要应用:返回输出随机图片


具体实现:
访问servlet,输出随机图片
private static final int WIDTH = 120;
private static final int HEIGHT = 25;
public static void randomPic(HttpServletResquest resquest,HttpServletResponse 
response) throw IOException
{
//构建一个随机图片(内存中)
BufferedImage image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
//拿到画图片的画笔对象
Graphic g = image.getGraphic();


//1、设置背景色
setBackGround(g);


//2、设置边框
setBorder(g);


//3、画干扰先
drawRandomLine(g);


//4、写随机数
drawRanodmNum(g);


//5、图形写给浏览器
response.setContextType("image/jpeg");//这句话是告诉浏览器返回的数据类型
response.setHeader("Cache-Control","no-cache");//不要缓存
response.setHeader("exprisef",-1);设置浏览器不要缓存


让浏览器知道解析成什么类型的数据格式
ImageIO.write(image,"jpg",response.getOutputStream());



}

//设置背景颜色
public void setBackGround(Graphic g)
{
g.setColor(Color.WHITE);
g.fillRec(0,0,WIDTH,HEIGHT);


}


//设置边框
public void setBorder(Graphic g)
{
g.setColor(Color.BLUE);
g.drawRec(1,1,WIDTH-2,HEIGHT-2);
}


//设置干扰线
public void drawRandomLine(Graphic g)
{
g.setColor(Color.GREEN);

for(int i = 0;i<5;i++)
{
int x1 = new Ranodm().nextInt(WIDTH);
int y1 = new Ranodm().nextInt(HEIGHT);

int x2 = new Ranodm().nextInt(WIDTH);
int y2 = new Ranodm().nextInt(HEIGHT);
g.drawLine(x1,y1,x2,y2);
}
}


public void drawRanodmNum(Graphic g)
{
g.setColor(Color.RED);
g.setFont(new Font("宋体",Font.BOLD,20);


String base = "\u4e00常用汉字uncode编码";
int x = 10;
for(int i =0;i<4;i++)
{
//随机生成汉字
String ch = base.charAt(new Random().nextInt(base.length()))+"";
g.drawString(ch,x,20);//10代表的是x轴的值,是变化的,要设置成变量
x+=30;


}
}




//能够完成使字体旋转的方法
public void drawRanodmNum_2(Graphic2D g)
{
g.setColor(Color.RED);
g.setFont(new Font("宋体",Font.BOLD,20);


String base = "\u4e00常用汉字uncode编码";
int x = 10;
for(int i =0;i<4;i++)
{
//随机生成汉字
String ch = base.charAt(new Random().nextInt(base.length()))+"";

int degree = new Random().nextInt()%30;//随机生成30以内的一个整数-30-30以内
g.rotate(degree*Math.PI/180,x,20);//设置旋转角度
g.drawString(ch,x,20);//10代表的是x轴的值,是变化的,要设置成变量
g.rotate(-degree*Math.PI/180,x,20);//转完之后转回来。保证下一个正常转


x+=30;


}



}






页面:
实现点击图片换图片的效果:
<img src = "/day06/servlet/responseDemo4" onclick = "changeimage(this)" alt="换一张" style="cursor:hand"/>
function changeimage(img)
{
img.src = img.src +"?"+new Date().getTime();
}
注意:刷新的作用就是1、将上次做的事情重新做一次。2、无论是否有缓存,都向服务器发请求




4、控制浏览器定时刷新
public void refresh(HttpServletRequest request,HttpServletResponse response) 
throws Exception
{
response.setHeader("refresh","3");//设置浏览器定时刷新


String data = new Random().nextInt(100000)+"";


System.out.println(data);
}


假设一个登陆或注册的页面,停留3秒跳转:
实用的自动跳转处理方式:
String message = "<meta http-equiv='refresh' content='3;url=/day05/index.jsp'>
恭喜你,登陆成功。本浏览器将在3秒后,自动跳转。如果没有跳转,请点击链接
<a href=''>超链接</a>";


this.getServletContext().setAttribute("message",message);
this.getServletContext().getRequestDispatcher("/message.jsp").forward(req,res);


5、控制浏览器禁止缓存,比较简单。
实际使用案例:ResponseDemo6控制浏览器缓存
servlet控制浏览器缓存:如果浏览器请求服务器的servlet获取数据,若拿到的数据不经常变,
就可以只请求一次,然后以后的一段时间呢就拿缓存内的数据。
public void cache(HttpServletRequest request,HttpServletResponse response) 
throws Exception
{
//设置浏览器端缓存的停留时间的长短
response.setDateHeader("expires",System.currentTimeMillis()+1000*3600);
。。。处理数据。。。

}


6、通过response实现请求重定向:你找我借钱,我没有,我让你去找别人。
实际使用案例:ResponseDemo6实现请求重定向
重定向的特点:1、浏览器会向服务器发送两次请求,意味着就有两对req,res
2、用重定向技术,浏览器地址栏地址会发生变化。
注意:重定向会向服务器发送两次请求,一般情况下不建议使用。
如果在登陆的作用上,就要用重定向。登陆成功后,跳转到首页,或者用户界面。
原因:登陆成功后,重定向会使地址栏地址发生变化,提示用户,体验比较好。
另外一种必须用重定向的:购物的时候,购买后,会跳转到购物车显示页面,这里也要用重定向


public void dispacther(HttpServletRequest request,HttpServletResponse response)
throws Exception
{
response.setRedirect("/day06/index.jsp");//这个就是重定向
}


7、ResponseDemo7
public void OutputStreamAndWriter(HttpServletRequest request,HttpServletResponse response)
thorws Exception
{
response.getOutputStream();//1获取输出流


response.getWriter();//2获取写入流。。。这两个方法不能同时调用。调用了会抛异常
//转发的情况下常常报出这个异常。。。一定要注意。。。切记。。。时间长了看到异常就想
//这个错误。。回头检查调用链排查就可以了。。。


}






HttpServletRequest(接口),由服务器创建请求对象:代表浏览器的请求对象。
URI(父):全球统一资源定位符,如:http://www.sina.com.cn.开发过程中用的多.
URL(子): 资源路径。/news/index.html


request的常用的方法:
1)request.getRequestURI();做权限拦截,页面访问次数等都会用到这个
2)request.getRequestURL();这个方法倒不是很常用
3)request.getQueryString();获取到查询的参数
4)request.getRemoteAddr();获取请求的ip地址
5)request.getRemoteHost();获取请求端的主机名
6)request.getRemotePort();获取请求端的端口
7)request.getLocalAddr();获取服务器的ip地址
8)request.getMethod();获取客户端的请求方式


1、获取请求头信息和请求数据RequestDemo1
public void reqMessage(HttpServletRequest request,HttpServletResponse response)
throws Exception
{
String headValue = request.getHeader("Accept-Encoding");
Enumeration e = request.getHeaders();
while(e.hasMoreElement())
{
String value = (String)e.nextElement();
System.out.println(value);
}


e = request.getHeaderNames();


}
2、客户机带数据给服务器的形式?
1)通过超链接的方式:<a href = "/day06/servlet/RrquestDemo1?name=..">..</a>
2)通过表单的方式向服务器提交数据
<form action ="/day06/servlet/RequestDemo1" method="post" >
<input type= "text" name="name" />
<input type = "submit" value = "提交"/>
</form>
服务器端获取提交数据的方式:
Enumration e = request.getParameterNames();
while(e.hasMoreElements())
{
String name = (String) e.nextElement();
String value = request.getParameter(name);


System.out.println(name+"..."+value);
}


获取同名的所带的数据值2
String [] arr = request.getParameters("name");
for(int i = 0;arr!=null&&i<arr.length;i++)
{
System.out.println(arr[i]);
}//这里之所以不用增强for循环,并且判断非空,也是为了程序的健壮性考虑
获取携带数据方式3
String [] values = request.getParameterValues("name");
..输出
获取携带数据方式4
Map<String,String[]> map = request.getParameterMap();//代表value的参数是数组
User user = new User();
BeanUtils.populate(User,map);
..注意有异常需要捕获或者声明
获取携带数据方式5
InpuStream in = request.getInputStream();
int len = 0;
byte buffer [] = new byte[1024];
while((len=in.read(buffer)!=-1)
{
System.out.println(new String(buffer,0,len);
}


非常重要的知识点:收集用户的数据。。通过表单搜集用户数据






request对象的中文乱码问题:
String name = request.getParameter("name");
name = new String(name.getByte("ISO8859-1","UTF-8"));




request对象实现请求转发。同时request是个域对象,其作用范围是请求范围。
其主要应用在MVC模式的开发中.


String data = "data";

//request实现携带数据
request.setAttribute("data",data);//这个就不会存在线程安全问题,因为request域
的作用范围是request范围(请求范围),即使转发了也是在一个请求范围之内。
//request实现请求转发
request.getRequestDispatchar("/message.jsp").forward(request,response);
Jsp页面的写法:
<%
String data = (String)request.getAttribute("data");
out.wirte(data);//输出到jsp页面
%>


开发常见的异常:IllegalStateException
String data = "data";


1、这样写会报下面的错。
PrinteWriter write = new PrintWriter();


write.write(data);
write.close();
//下面的跳转会产生异常IllegalStateException。。。跳转之前不能向客户机写数据。。
request.getRequestDispatchar("/message.jsp").forward(request,response);
2、这样写也会报下面的错。。
if(true)
{
request.getRequestDispatchar("/index.jsp").forward(request,response);
}


//下面的跳转会产生异常IllegalStateException。。。跳转之前不能向客户机写数据。。
request.getRequestDispatchar("/message.jsp").forward(request,response);


如何改正呢,请求转发后就弄一个return,如下:
if(true)
{
request.getRequestDispatchar("/index.jsp").forward(request,response);
return;
}

forward的细节:forward时,会清空response中的数据
String data = "data";
response.getWriter().write(data);


request.getRequestDispatcher("/index.jsp").forward(req,res);


request的另一个应用:防盗链
public void method(req,req) throws IOException
{
String referer = request.getHeader("referer");
if(referer==null||referer.startWith("http://localhost"))
{
response.sendRedirect("/day06/index.jsp");
return ;重定向后面的代码不需要执行,直接return,下面的代码不执行
}
String data = "凤姐日记";
response.getWriter().write(data);
}

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值