JavaWeb---Servlet

Servlet API有以下4个Java包:
javax.servlet:其中包含定义Servlet和Servlet容器 之间的锲约类和接口
javax.servlet.http:其中包含定义HTTP Servlet和Servlet容器 之间的契约类和接口
javax.servlet.annotation:其中包含标注Servlet,Filter,Listener的标注 ,它还为被标注元件定义元数据

Servlet简介

Servlet的主要功能在于交互式的浏览和修改数据,生成动态的web内容,Servlet具有更高的效率,功能强大,具有更好的可移植性。

Servlet架构

浏览器发送http协议请求,Servlet程序中通过一系列ServletAPI读取http协议,对浏览器的请求进行处理,通过访问服务器和文件,拿到数据后发送对浏览的响应。Servlet程序会放在一个web服务器(容器)中。

servlet中主要执行以下操作
1.获取前台页面传递过来的参数数据
2 调用service层,调用DAO(Data Acess Object)层
3.将数据存储到域
4.跳转到前台页面
Servlet是一个单实例多线程的,在内存中只会创建一次servlet对象,存在多线程的安全问题
在这里插入图片描述

Servlet实现

注解出现在JDK5以后。
Servlet是一个接口,定义服务端程序的实现方法,它是所有Servlet类必须直接或间接实现的接口。Servlet实现类与接口的关系如下:

在Java中,利用web容器,例如tomcat来处理http协议。

httpServlet中的doget()方法的实现内容:首先会调用http协议,判断处理的协议版本,如果处理的http协议版本是1.1,则返回响应为405状态码错误(这样做是提醒编程人员需要自己实现get方法的内容,调用父类的doget()方法就会报错);如果处理的http协议版本是1.0,则返回响应为400状态码的错误.

httpServlet中的service()方法的实现内容:判断httpServlet中的请求是否是doGet()/doPost()/doPut()/doDelete()等方法,然后将请求转发到相应的方法实现中,由于子类继承了httpServlet,因此最终调用的是子类中对各种方法的实现逻辑。

Servlet方法

init,service,destroy 是Servlet的生命周期方法.

  • init:当service容器第一次被请求时,Servlet容器会调用该方法,后续请求不会被继续调用
  • service:每当请求Servlet时,Servlet容器就会调用这个方法。(可多次调用)
  • destroy:当要销毁Servlet时,Servlet容器就会调用该方法。(一次调用)

线程安全问题:一个Servlet类只有一个Servlet实例,Servlet实例会被一个应用程序中的所有用户共享,如果出现多个浏览器客户端访问Servlet,那么这些用户都会访问同一个实例,可能会造成结果混乱,因此在Servlet中尽量不使用类的成员变量。

ServletConfig

当当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init方法传入一个ServletConfig。ServletConfig封装可以通过部署描述符(需要在web.xml文件中配置init-param属性值)传给Servlet的配置信息。这样传入的每一条信息就叫做初始化参数,一个初始化参数有key和value组成。

<init-param>
<param-name>logFileName</param-name>
<param-value>filter.logging</param-value>
</init-param>

为了从Servlet内部获取到初始化参数的值,要在Servlet容器传给Servlet的init方法的ServletConfig中调用getInitParameter方法即可。

ServletContext

ServletContext表示Servlet应用程序。每个Web应用程序只有一个上下文,在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象,就可以共享从应用程序中的所有资料处访问到的信息,并且可以动态注册Web对象,共享信息可以将对象保存在ServletContext中的一个内部Map中,保存在ServletContext中的对象被称作属性
通过ServletConfig中调用getServletContext方法,可以获得ServletContext。

HttpServletRequestAPI

获取请求方法: String method=req.getMethod();
获取请求uri: req.getRequestURI();
请求的协议版本: req.getProtocol();
获取指定的请求头信息: req.getHeader("host");
获取user-agent请求头req.getHeader("user-agent");会返回字符串,包含浏览器类型信息

Trisent:IE浏览器
Chrome:谷歌浏览器
firefox:火狐浏览器

以get方式提交请求时获取参数 数据:String queryString=req.getQueryString();
get方式会将请求信息放在地址栏中,get方法中的内容是有限制的。因此get方法一般用于数据查询。

以post方式提交请求时获取参数数据

InputStream in=   req.getInputStream();
        byte[] bytes=new byte[1024];
        int len=in.read(bytes);
        while(len!=-1){
            System.out.println(new String(bytes,1,len));
        }

post方式是以二进制字节数据向服务器发送请求的

get方式与post方式通用的获取参数的方式一
通过表单的name参数值获取表单内容,因此html中的表单一定要定义表单属性
获取所有参数值:Enumeration<String> enums= req.getParameterNames();

get方式与post方式通用的获取参数的方式二
通过指定参数名称获取参数值:req.getParameter("name");

get方式与post方式通用的获取参数的方式三
获取所有参数对象,返回值为map集合,key值为参数对象(String接收),value为参数值(参数值可以为多个,如表单为复选框的情况,用String[]):

Map<String,String[]> paraMap= req.getParameterMap();

get方式与post方式通用的获取参数的方式四
通过参数名,获取多个参数值:String[] habits= req.getParameterValues("habit");

tomcat8.0以下的版本,利用get()方法提交时:遇见参数为中文,需要手动解码,因为在表单中的信息是以UTF-8编码的,tomcat服务器是以iso-8859-1的方式编码的,若不进行解码会出现乱码的情况
手动解码:String name= req.getParameter(“name”);
name=new String(name.getBytes(“iso-8859-1”),“utf-8”);

使用post()方式提交请求时,解码的方法为: req.setCharacterEncoding(“utf-8”);

一般为了防止冲突,使用这些通用方法获取参数时会在doPost()方法中复用doGet()方法(获取参数的方法一般写在doget()中)

浏览器的编码可能与程序的编码不同,所以一般要将从浏览器获取的信息进行编码转化。

String name=req.getParameter("name");
new String(name.getBytes("ISO-8859-1"),"utf-8");

HttpServletResponseAPI

设置编码resp.setContentType("text/html;charset=utf-8");
向浏览器输出内容resp.getWriter().write("hello,这是我的第一个Servlet");
使用字节流的方式向浏览器输出内容(图片文件,音频视频)response.getOutputStream().write("hello,response".getBytes());

设置响应头setHeader("name","val)
设置响应的状态码response.setStatus(404); 访问不到servlet:

200 响应成功
500 服务器有问题(出现的各种异常)
404 一般情况:路径有问题 (url-pattern:路径对不上) :404状态+404错误页面
406 :异步请求出现的问题
400 项目下找不到资源
302 :进步一步请求 +location响应头 :

重定向

 //重定向原理
		// 设置状态302
        resp.setStatus(302);
        //设置location响应头
        resp.setHeader("location","adv.html");

当浏览器输入url向服务器发送请求时,服务器创建Servlet对象,调用了doGet()方法后,读到了302状态码,就会携带响应头地址resp.setHeader("location","adv.html");响应回给浏览器,浏览器会进一步访问,向服务器请求adv.html地址;所以一共有两个request对象,且不相等,因为两个请求携带的数据不同。
在实际应用中其实没有这么麻烦,在tomcat中配置web applecation的上下文路径(工程名称),就可以直接跳转resp.sendRedirect("/项目名称/资源文件名称");
重定向的地址栏会发生变化,跳转到指定的页面上。

请求转发: req.getRequestDispatcher("adv.html").forward(req,resp);
请求转发还是会处在请求的地址栏,是服务器的行为,request对象只有一个

设置定时刷新

resp.setHeader("Refresh","2");

设置编码格式:resp.setContentType("TEXT/HTML;charset=utf-8");

以指定方式打开资源:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        File file=new File("");
        //以下载方式打开资源
        resp.setHeader("Content-Disposition","attachment;filename="+file.getName());
        //下载文件
        //创建字节流输入对象
        InputStream in=new FileInputStream(file);
        //获取字节输出流对象
        OutputStream out=resp.getOutputStream();
        //边读边写
        byte[] buff=new byte[1024];
        int len=0;
        while((len=in.read(buff))!=-1){
            out.write(buff,0,len);
        }
        in.close();
        out.close();
    }

(面)Servlet生命周期

Servlet的执行过程:

  1. http://localhost:8080/hello-->
    在网站配置web.xml文件中中找是否存在一个映射url-pattern: /hello
  2. 如果找到,去servlet-maping中的servlet-name:找到对应的类名称HelloServlet,再在**配置信息(servlet标签)**中找是否存在同名的一个HelloServlet,
  3. 访问Servlet-class---->通过反射获取到HelloServlet.class 类对象 (重点)

反射机制:
创建类对象
1.Class classz=Class.forName("com.github.sweeeeeet.tomcat.HelloServlet");
2.通过数据类型的class属性获取class对象String.class
3.Object类中getClass()方法

获取Constructor 对象
Constructor con=classz.getDeclaredConstructor("构造函数的参数类型");
获取实例
Object obj=con.newInstance();
加载具体方法
Method m1=classz.getDeclaredMethod("init",ServletConfig.class);
m1.invoke(obj,config)

  1. 反射机制获取到成员方法---->tomcat解析里面内容

servlet初始化

servlet配置信息,初始化参数,或servlet加载机制
public void init(ServletConfig config)

简易初始化方法(用户自定义初始化信息时使用)
public void init()

servlet执行请求发送响应
tomcat服务器获取到浏览器的请求数据,会将请求数据封装到HttpServletRequset对象中,tomcat调用service方法,业务具体覆盖doGet()方法或doPost()方法(开发者做的事情)

业务服务protected void service(一般不会覆盖service 方法,会将逻辑写在doGet()或doPost()方法中)

  1. 使用HttpServletResponse响应给用户内容

  2. 销毁public void destroy()

销毁的几种情况
System.exit(0);
jvm停止运行

ServletConfig对象API

ServletConfig是servlet配置对象,在处理逻辑doGet()/doPost()方法中,若需要频繁改动处理逻辑,可以将其放入到servlet配置信息中作为初始化参数,一个servlet 中可以使用多个ServletConfig对象,只需要在web.xml文件中配置init-param,在servlet标签中可以包含多个init-param

<init-param>
    <param-name>path</param-name>
    <param-value></param-value>
</init-param>

同时还可以设置servlet的加载时机:<load-on-startup>2</load-on-startup>

  • 数值越大,优先级越低

获取ServletConfig对象ServletConfig con=this.getServletConfig()
通过参数获取ServletConfig对象的值String path=fig.getInitParameter("path");

ServletContext对象API

作用:
1.获取上下文路径

ServletContext context=this.getServletContext();

2.可以请求转发(跳转页面)

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

           RequestDispatcher rd= context.getRequestDispatcher("/hello.html");
		   rd.forward(req,resp);
//简写方式
//req.getRequestDispatcher("hello.html").forward(req,resp);
    }

请求转发和重定向的区别:
1.转发请求地址不会发生变化,重定向本质上是进一步请求,因此地址会发生变化
2.请求转发在业务中跳转页面,需要用到域对象(request域);重定向无法从request域中获取数据
3.内存角度:请求转发始终只有一个request对象;重定向会产生两个不同的request对象

3.作为一个域对象使用

域对象:共享数据,在不同的jsp/servlet之间保存数据,获取数据
常见的域有:
PageContext(jsp中的域对象,但是仅限于当前页面的jsp)—pageScope对象
HttpServletRequest—requestScope对象
HttpSession—sessionScope对象
ServletContext—applicationScope对象(最大的一个域)

在一个servlet中设置数据:context.setAttribute(String var1, Object var2);
在另一个servlet中获取数据:context.getAttribute(String s)

4.获取真实路径

        ServletContext context=getServletContext();
        context.getRealPath("a.txt");
//其他获取路径的方法
        PathDemo.class.getClassLoader().getResource("a.txt");

5.获取全局参数

1.String con = context1.getInitParameter("name");
2.Enumeration<String> s= context1.getAttributeNames();

应用:
表单提交:

public class FormServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer=resp.getWriter();
        writer.append("<html>")
                .append("<head>")
                .append("<title>")
                .append("登录")
                .append("</title>")
                .append("</head>")
                .append("<body>")
                .append("<form action='handlerServlet' method='post'>")
                .append("username:<input type='text' name='username'/></br>")
                .append("password:<input type='password' name='password'/></br>")
                .append("<input type='submit' value='submit'>" )
                .append("<input type='reset' value='reset'>")
                .append("</form>")
                .append("</body>")
                .append("</html>");
    }
}

配置XML文件


    <servlet>
        <servlet-name>FormServlet</servlet-name>
        <servlet-class>com.sweet.github.servlet.httpservlett.FormServlet</servlet-class>

    </servlet>
    <!-- Servlet的映射关系,告诉tomcat容器,当用户请求一个地址的时候,使用该Servlet处理 -->
    <servlet-mapping>
        <servlet-name>FormServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

文件上传:

public class UpoadFile extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Part part=req.getPart("filename");
        InputStream is= part.getInputStream();
        String appUploadPath = req.getServletContext().getRealPath("/upload");
        File file=new File(appUploadPath,part.getSubmittedFileName());
                if(!file.getParentFile().exists()){
            file.getParentFile().mkdirs();

                }
        OutputStream out=new FileOutputStream(file);
        byte[] buff=new byte[1024];
        int len=-1;
        while ((len=is.read(buff))!=-1){
            out.write(buff,0,len);

        }
        out.close();
        is.close();
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter writer=resp.getWriter();
        writer.append("<html>")
                .append("<head>")
                .append("<meta charset='UTF-8'>")
                .append("<title>File</title>")
                .append("</head>")
                .append("<body>")
                .append("<a href='>")
                .append("/upload/").append(part.getSubmittedFileName())
                .append("'>")
                .append("上传的文件")
                .append("</a>")
                .append("</body>")
                .append("</html>");


    }
}

配置xml文件

<servlet>
        <servlet-name>UpoadFile</servlet-name>
        <servlet-class>com.sweet.github.servlet.httpservlett.UpoadFile</servlet-class>
        <multipart-config>
            <location>D:/upload</location>
            <max-file-size>1048576</max-file-size>
        </multipart-config>
    </servlet>
    <servlet-mapping>
        <servlet-name>UpoadFile</servlet-name>
        <url-pattern>/upload</url-pattern>
    </servlet-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值