重要的API
重要的API
config
- init()和init(ServletConfig config)
getInitParameter():String
getServletConfig().getInitParameter("height")
response响应
HttpServletResponse接口属于Servlet规范,存在于servlet-api.jar中,由服务器提供接口的实现类,主要用于封装服务器的响应信息,可以将doGet或doPost的响应信息写出到【响应体】中
- ServletResponse隐藏了向浏览器发送响应的复杂过程
响应头的相关操作
addHeader(String name, String value) / addIntHeader(String name, int value) /addDateHeader(String name, long date)
- Content-Disposition Expires Cache-Control
setHeader(String name, String value) / setDateHeader(String name, long date) / setIntHeader(String name, int value)
其中,add表示添加,而set表示设置
响应输出流的操作
PrintWriter getWriter()获得字符流,通过字符流的write(String s)方法可以将字符串设置到response 缓冲区中,随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端。
response.setContentType("text/html;charset=utf-8");
PrintWriter out=response.getWriter();
out.println("<html>....</html>"); //可以输出html文档
out.flush();
out.close();
ServletOutputStream getOutputStream()获得字节流,通过该字节流的write(byte[] bytes)可以向response缓冲区中写入字节,再由Tomcat服务器将字节内容组成Http响应返回给浏览器。
需求:动态生成验证码—防止机器人
具体应用使用组件
public class PicServlet extends HttpServlet {
private int width=120,height=40;
//允许在web.xml中针对图片的高和宽进行配置
public void init() throws ServletException {
String ss=this.getServletConfig().getInitParameter("width");
try{
width=Integer.parseInt(ss);
}catch (Exception e){
width=120;
}
ss=this.getServletConfig().getInitParameter("height");
try{
height=Integer.parseInt(ss);
}catch (Exception e){
height=40;
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedImage img=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
Graphics paint=img.getGraphics();
paint.setColor(new Color(200,200,100));
paint.fillRect(0,0,width,height);
paint.setColor(Color.black);
paint.drawRect(2,2,width-6,height-6);
//绘制动态验证码
String checkcode=this.generateCode(6);
System.out.println(checkcode);
paint.setColor(Color.red);
paint.setFont(new Font("宋体",Font.BOLD,28));//设置绘制字符所使用的字体
paint.drawString(checkcode,10,height-10);
//绘制杂点或者扰动线,避免OCR图像识别
paint.dispose();
//告知浏览器如何处理响应内容
response.setContentType("image/jpeg");
ServletOutputStream sos=response.getOutputStream();
//输出为JPG格式
ImageIO.write(img,"jpg",sos); //通过输出的字节流输出jpg格式的图片
sos.flush();
sos.close();
}
//生态动态验证码
private String source="abcdefghijklmnopqrstuvwxyz1234567890";//在验证码中允许出现的字符范围
private String generateCode(int len){
Random r=new Random();
StringBuilder sb=new StringBuilder();
for(int i=0;i<len;i++){
int pos=r.nextInt(source.length());
sb.append(source.charAt(pos));
}
return sb.toString();
}
}
web.xml的Servlet和Servlet初始化参数的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>PicServlet</servlet-name>
<servlet-class>com.yan.action.PicServlet</servlet-class>
<init-param>
<param-name>width</param-name>
<param-value>200</param-value>
</init-param>
<init-param>
<param-name>height</param-name>
<param-value>60</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>PicServlet</servlet-name>
<url-pattern>/pic.do</url-pattern>
</servlet-mapping>
</web-app>
客户端缓存
思路:使每次访问URL都不一致,引入一个没有用的额外参数
<body onload="ff()">
<form action="login.do" method="post">
<input name="checkcode"/>
<img id="img1"/>
<script>
function ff(){
document.getElementById("img1").src='pic.do?q='+Math.random();
}
</script>
</form>
</body>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
服务器端设置避免客户端缓存
response.setContentType("image/jpeg");
response.setHeader("Pragma","no-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires",0);
ServletOutputStream sos=response.getOutputStream();
... ...
其它操作
指定浏览器解析页面的编码方式setContentType(String type),这里的类型定义type采用的是MIME格式的规范
- text/html表示是一个html格式的文本文档
- image/jpeg表示是一个jpg格式的图片文档
response.setContentType("text/html;charset=utf-8");
设置响应行状态码setStatus(int sc)
- 200 OK
- 404
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setStatus(404);
}
sendError(int sc, String msg)设置报错状态码,例如404,String是自定义的报错信息
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(404,"张前端来了!");
}
如何自定义报错页面
- 一般是应用完成后给客户提交之前配置的,主要作用是隐藏各种报错信息
- 如果开发过程中不建议配置
web.xml中允许配置在当前应用中报错处理页面
<!--在当前应用中如果出现404异常时,自动跳转abc.html页面-->
<error-page>
<error-code>404</error-code>
<location>/abc.html</location>
</error-page>
可以在当前应用中全局配置针对指定异常的报错页面
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int k=0;
System.out.println(10/k);
}
默认报错为【HTTP状态 500 - 内部服务器错误】
<!-- 在当前应用中如果出现Exception类型的异常则自动跳转bbb.html页面-->
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/bbb.html</location>
</error-page>
request请求
HttpServletRequest接口类型,属于Servlet规范,存在于servlet-api.jar中,由服务器提供接口的具体实现类
- 主要用于封装用户的请求数据
- Servlet容器对于接受到的每一个Http请求,都会创建一个ServletRequest对象,并把这个对象传递给Servlet的Sevice( )方法。其中,ServletRequest对象内封装了关于这个请求的许多详细信息
- request对象是从发起请求开始创建,生成响应完毕后销毁
请求头数据
long getDateHeader(String name) / String getHeader(String name) /int getIntHeader(String name)
Enumeration getHeaderNames() / Enumeration getHeaders(String name)
referer头的作用:执行该此访问的的来源,做防盗链
- 图片水印
- 盗链页面
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//如果地址栏中直接访问,则返回为null;如果有上一个页面,则返回该页面的地址,例如http://localhost:8080/demo3_war_exploded/login.html
String referer=request.getHeader("referer");
System.out.println(referer);
}
###请求参数
get采用的是协议头的方式传递数据,数据格式为abc.do?username=zhangsan&password=123
post采用的是协议体的方式传入数据,请求体中的内容是通过post提交的请求参数,格式是:username=zhangsan&password=123
String getParameter(String name)
String sage=request.getParameter("age"); //传递各种数据类型时只能接收到String或者String[]类型
Integer age=null;
try{
age=Integer.parseInt(sage);
}catch(Exception e){
age=null;
}
//if(age==null) 如果要求必须正确的age提交参数的报错处理,如果age值可有可无,则不做处理
String[] getParameterValues(String name)
Enumeration getParameterNames()
Map<String,String[]> getParameterMap()
Request乱码问题的解决方法
在service中使用的编码解码方式默认为ISO-8859-1编码,但此编码并不支持中文,因此会出现乱码问题,所以我们需要手动修改编码方式为UTF-8编码,才能解决中文乱码问题
中文乱码的3种解决方案:
- 针对post请求
<meta charset="GBK">
<form action="test.do" method="post">
<input name="name"/>
<input type="submit" value="提交数据"/>
</form>
java编程接收数据的处理
//设置请求编码字符集必须在所有获取请求参数之前,否则设置无效
request.setCharacterEncoding("GBK"); //这里编码字符集必须和提交数据的页面编码字符集一致
String ss=request.getParameter("name");
System.out.println(ss);
- 针对get请求
修改Tomcat的配置server.xml,添加一个配置参数URIEncoding=“GBK”
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding="GBK" redirectPort="8443" />
- 通用解决方案
String ss=request.getParameter("name");
ss=new String(ss.getBytes("ISO-8859-1"),"GBK");
System.out.println(ss);
###其它方法
获得客户端的请求方式:String getMethod()
参照HttpServlet类中service方法的实现—模板模式
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod(); //获取请求方法,按照http1.1协议有8种不同的请求方法,例如get、post、delete、put等
if (method.equals(METHOD_GET)) {
doGet(req, resp);//如果请求方法是GET时,则调用doGet,在HttpServlet类中声明了方法,但是没有具体的实现,实现延迟到具体子类中进行覆盖定义
} else if (method.equals(METHOD_HEAD)) {
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
public abstract class BaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
if(action==null ||action.trim().length()<1)
action="show";
try {
Class clz = this.getClass();
Method method = clz.getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
method.invoke(this,req,resp);
} catch (Exception e) {
throw new ServletException(e);
}
}
public abstract void show(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
}
用户CRUD操作
public class UserServlet extends BaseServlet {
@Override
public void show(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//路径是user.do?action=show或者user.do
}
public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//路径是user.do?action=add
}
public void del(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//路径是user.do?action=del
}
public void load(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//路径是user.do?action=load&id=1
}
public void modify(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//路径是user.do?action=modify
}
}
OOP编程原则:
- 要求类内高内聚、类间弱耦合
- 将一个用户的相关操作定义在4个不同的Servlet类中
- 解决方案:引入一个额外的动作参数
获得请求的资源:
String getRequestURI() /demo3/test.do 不会包含get请求的参数
StringBuffer getRequestURL() http://localhost:8080/demo3/test.do
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(request.getRequestURI());
}
String getContextPath() —web应用的名称 /demo3
String getQueryString() ---- get提交url地址后的参数字符串 //id=123&name=yanjun
Java反射基础
构建对象
//构建一个对象,类名称是作为字符串类型的参数进行指定
Object obj=Class.forName("com.yan.action.Test2").newInstance(); //等价于new Test2();
调用方法
//构建一个对象,类名称是作为字符串类型的参数进行指定
Object obj=Class.forName("com.yan.action.Test2").newInstance();
//获取类的引用
Class clz=obj.getClass();
//查找指定的方法,参数1:方法名称为字符串类型,后续参数就是该方法的参数类型
Method method=clz.getDeclaredMethod("pp",Integer.class);
//调用查找到的方法,参数1是方法所在的对象,如果有参数才有后续的参数,后续参数就是调用方法时的实参
Object res=method.invoke(obj,10);
System.out.println(res); //null