Servlet2

重要的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

JSP技术

JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准,它实现了在HTML标签中使用Java代码

JSP是一种动态网页技术标准,也是JavaEE的标准。JSP和Servlet一样,是在服务器端执行的。JSP是在Servlet技术发展之后为了让开发者写html标签更方便而发展起来的技术,JSP实际上就是Servlet。但是通常把Servlet作为Web应用中的控制组件来使用,只负责响应请求产生数据,并把数据通过转发技术带给jsp,而把jsp技术作为数据显示模板来使用。这样使程序结构更清晰,可读性和可维护性更高。

Hello JSP

究其本质jsp页面就是包含Java代码的html网页

1、编写一个html网页

  • 执行访问不会在work文件夹下生成任何内容

2、将html后缀修改为.jsp

  • 自动在work下生成了两个文件,一个名为index_jsp.java,另外一个名为index_jsp.class
  • jsp并不能直接执行,需要先通过jsp引擎将jsp文件转换为servlet的类文件,然后通过Servlet引擎将servlet类文件编译为.class字节码文件,然后才能执行并生成html文档

3、可以在jsp文件中使用java语言编写相关的脚本程序

<table width="80%">
	<caption>99</caption>
	<%
	for(int i=1;i<10;i++){
	%>
	<tr>
		<%
			for(int k=1;k<=i;k++){
		%>
		<td><%=k%>*<%=i%>=<%=i*k%></td>
		<%}%>
	</tr>
	<%
		}
	%>
</table>

JSP基础语法

###注释

从软件工程化管理上说,不写注释是不合理的,一般建议编程中20%-30%左右的编码量为注释

JSP注释

<%-- 多行内容 --%> 会被编译器所忽略,其中可能有语法错误,但是不影响编译

html注释

<!--多行内容-->其中的内容会被编译执行,只是在浏览器中不进行显示

###模板元素

直接写在jsp页面的html内容称之为jsp页面的模板元素;模板元素在翻译过来的servlet中被out.write()原样输出到浏览器中

out.write("<table width=\"80%\">\r\n");
      out.write("\t<caption>99</caption>\r\n");
      out.write("\t");

	for(int i=1;i<10;i++){
	
      out.write("\r\n");
      out.write("\t<tr>\r\n");
      out.write("\t\t");

			for(int k=1;k<=i;k++){
		
      out.write("\r\n");
      out.write("\t\t<td>");
      out.print(k);
      out.write('*');
      out.print(i);
      out.write('=');
      out.print(i*k);
      out.write("</td>\r\n");
      out.write("\t\t");
}
      out.write("\r\n");
      out.write("\t</tr>\r\n");
      out.write("\t");

		}
	
      out.write("\r\n");
      out.write("</table>");

###JSP表达式 --取值

常量 : <%=“hello”%>

<% int k=100; %>
<%=k%>   转换的结果为out.write(k);
  • 不能定义合法的java代码,因为out.write()的原因
  • 不能定义方法,因为代码段中的内容会出现在public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
  • 可以通过匿名内部类的方式定义类
  • 注意:默认不能有;号

变量 :<%String name=“aa”;%> //定义变量

​ <%=name%> //取变量的值

  • <%%>之间应该是合法的java语句,允许定义多行程序
  • 不允许直接定义方法,不允许定义属性,可以定义临时变量,可以通过内部类的方式定义类【方法中允许定义类】
<%
	int res=0;
	for(int i=1;i<=100;i++)
		res+=i;
%>
<h3>1+2+3+...+100=<%=res%></h3>

对应编译的结果为

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException {
    ... ...
    
        int res=0;
	for(int i=1;i<=100;i++)
		res+=i;

      out.write("\r\n");
      out.write("<h3>1+2+3+...+100=");
      out.print(res);
      out.write("</h3>");
    ....
}

代码段的编译结果会出现在_jspService方法内部

声明:

​ 语法规则: <%! 多行声明属性或者方法之类的内部成员 %>

<%! 
private int counter=0;
public void cc(){}
%>

编译生成的类定义

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {

 
private int counter=0;
public void cc(){}
  • 允许定义方法或者属性以及内部类
  • 允许定义静态代码块或者非静态代码块
  • 不允许直接写执行语句,例如out.println(100);
  • 不能定义临时变量

需求:

页面计数器:统计当前页面的访问次数

默认Servlet的运行特征为单实例多线程的方式运行service方法,而jsp运行前需要编译为类,所以运行特征也应该是单实例多线程的方式运行_jspService方法

<%@ page contentType="text/html;charset=utf-8" %>
<%! private int counter=0; %>
您是第<%=++counter%>位访问者

因为_jspService是以多线程的方式运行,修改counter可能会导致安全问题

<%@ page contentType="text/html;charset=utf-8" %>
<%! private static int counter=0; 
	public synchronized void pp(){
			counter++;
	}
%>
<% pp(); %>
您是第<%=counter%>位访问者,IP地址为<%=request.getRemoteAddr()%>

###3大JSP页面指令

位置: 可以写在JSP页面的任意位置

格式:<%@ 指令名称 若干属性声明%>

  • 使用IDEA开发页面的默认存储位置为src/main/webapp/目录下,允许自定义目录

####page指令 --用来声明当前JSP页面的基本属性

<%@ page language="java" %> – 指定当前JSP使用的语言是java

####pageEncoding和contentType

<%@ page pageEncoding="UTF-8"%> – 用来通知JSP解析引擎使用指定的编码来翻译JSP

注意:如果想防止JSP乱码,应该要保证JSP文件保存时的编码和pageEncoding指定的编码保持一致

<%@ page contentType="text/html;charset=utf-8" %>类似于response.setContentType(“text/html;charset=utf-8”)

从语义上说两个属性不是一回事,但是经常会相互替代

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
当前页面的异常处理

<%@ page errorPage="bbc.jsp"%>如果在当前页面中出现异常自动跳转的页面

JSP中9大默认对象:exception

<%@ page isErrorPage=“true” %>表示在当前bbc.jsp页面中可以通过exception对象获取前面出现的异常

具体实现有异常的页面bbb.jsp

<%@ page contentType="text/html;charset=UTF-8" errorPage="bbc.jsp" language="java" %>
<% 
int k=0;
out.println(10/k);
%>

定义bbc.jsp页面用于显示bbb.jsp页面种出现的异常

  • 要求必须设置参数<%@ page contentType="text/html;charset=UTF-8" isErrorPage="true" language="java" %>,如果不配置isErrorPage则不能使用exception默认对象

  • 显示方式1: <%=exception%>

  • 显示方式2:<% exception.printStackTrace(); %>在控制台上显示报错信息

  • 显示方式3:在页面上显示调用栈

    <%
        exception.printStackTrace(new PrintWriter(out));
    %>
    

作业:

上传下载的实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值