Javaweb

servlet学习笔记(一)

2018-09-26  本文已影响3人  panda_Hi

C/S模式的软件 客户端/服务器 比如QQ,或者一些大型游戏
用户需要先下载软件的客户端,然后才可以使用.

B/S模式的软件 浏览器/服务器 我们上网时候所访问网站
的基本全是B/S模式的项目.用户不需要下载任何东西,只需要
用到浏览器就可以访问到这个项目.

我们在java中要学习的web项目,就是B/S架构的项目.

web项目中,其实就是俩个软件之间的信息交换,客户端机器
中的浏览器软件和服务器端机器中的web服务器软件之间的
交换,比如在我们的学习中,就是客户端的浏览器和服务器端
的tomcat进行信息交换。

浏览器和tomcat是俩个不同的软件,但是在开发这俩个软件
的时候,都是加入对http协议的支持,所有它们俩个进行信
息交换的时候,是通过http协议规定的方式进行交换的:
客户端先发送一个请求,然后服务器端接收到请求后再返
回给客户端一个响应,并且把客户端所请求的资源返回给客户端.

我们要做的时候就是,开发一个web项目,然后把这个web项目
放到tomcat里面指的的位置,然后再运行这个tomcat软件,
在tomcat运行过程中,其他计算机里面,只要是网络和我们这
个服务器是通的,那么都可以通过浏览器来访问我们这个web项目。

在用浏览器访问tomcat的时候,tomcat会按照浏览器发送的
这个请求里面的内容,把浏览器想访问的页面从web项目中找
到并返回给这个浏览器,或者是tomcat去调用web项目所写
的某些java类中的方法(其实就调用servlet中的方法)

注意:web项目中,任何一个类里面都不需要写main方法,整个
项目的运行,对象的创建,方法的调用,都是由tomcat处理的,
我们不需要去管. tomcat根据客户端的要求,会调用某个
servlet中的指定方法,然后在这个指定方法里面,我们可
以写上调用我们自己写的某个类的方法,类似的这样方法相
互调用下去,最后调用到我们sql语句的执行,这样我们的
一个功能就走完了,比如说登录或者注册功能。

一个web项目最基本的项目结构:
项目名字:web_test
1.文件夹web_test,项目名字是随便起的

2.web_test文件中有文件WEB-INF,WEB-INF这个名字是固定的

3.WEB-INF文件夹中:classes文件夹,lib文件夹,web.xml文件,这个名字都是固定的。
web.xml文件在tomcat目录中的conf目录里面有一个web.xml模板.

注意:
web_test文件夹下面还可以放页面,css样式、js文件、图片,html等等.
classes文件夹中放的是编译后的.class文件
lib文件夹中放的是当前项目中运行所需要的jar包(私有,本项目可以使用的)

tomcat服务器:
bin 目录:启动、关闭tomcat相关的命令。
conf目录:tomcat的配置文件
lib 目录:tomcat中可以同时部署多个项目,多个项目都需要用到的相同jar包,就可以放在这个目录。
logs目录:记录tomcat日常运行的情况或者错误信息。
temp目录:tomcat运行期间可能会产生一些临时文件,这写临时文件就会放在这个目录.
webapps目录:我们开发好的web项目就是需要放到这个指定的目录下面,默认里面已经有一些tomcat自带的项目样例了.
work目录:编译jsp页面时候需要用到的一个目录.
jsp编译成的java代码及字节码存放的位置
session的序列化产物。
访问tomcat中项目里面的资源的方式:
http://IP:port/项目名字/项目在资源
http://localhost:8080/web_test/test.png
http://localhost:8080/web_test/form.html

localhost:8888/jd1812_web/images/test.png
localhost:8888/jd1812_web/css/test.css

手写一个servlet并且放到tomcat中去运行:

package com.briup.test;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;

import java.io.IOException;
import java.io.PrintWriter;
public class FristServletTest extends HttpServlet{
public void doGet(HttpServletRequest req,HttpServletResponse resp)throws ServletException,IOException{
PrintWriter out = resp.getWriter();
out.println("hello world");
out.flush();
out.close();
}

}

servlet-api.jar在tomcat的lib目录中

servlet-api.jar和FristServletTest.java都在桌面
编译java文件所在的命令窗口的路径也在桌面

javac -cp servlet-api.jar -d . FristServletTest.java

编译完之后,把这个.class文件已经包目录,放到项目中
的classes目录里面,然后再项目中的web.xml文件进行
配置,配置的目的是:想把一个路径映射成我们自己一个
servlet,这个我们在浏览器里面就可以用个这个映射
的路径来来访问这个servlet了.

浏览器的地址栏中只能提供类似于这样的信息:
主要是以路径的形式提供访问的信息:
/.../.../.../...
http://172.16.4.81:8002/WebTest/hello.html

但是我们需要的是这样的信息:
要运行servlet至少要有servlet的对象,所有我们需要这个类的package.类名
com.briup.test.FristServletTest

所以我们需要把一个路径映射成一个servlet:
比如:把/first路径映射成FristServletTest这个servlet,将来用户在浏览器中输入/first路径之后,就相当于告诉服务器,需要运行FristServletTest这个servlet.

例如:
web.xml文件中加入:
<servlet>
<servlet-name>firstservlet</servlet-name>
<servlet-class>com.briup.test.FristServletTest</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>firstservlet</servlet-name>
<url-pattern>/first</url-pattern>
</servlet-mapping>

<servlet>中的<servlet-name>子标签:
给你要描述的servlet起一个名字,这个是名字是随便起的,目的是为了在下面做映射的时候能够再找到这个servlet

<servlet>中的<servlet-class>子标签:
这个servlet的package.类名

<servlet-mapping>中的<servlet-name>子标签:
指明这个映射是给哪一个servlet的做的映射,通过之前随便起的servlet的名字找。

<servlet-mapping>中的<url-pattern>子标签:
这个就是我们要映射的路径,将来浏览器里面输入这个路径就相当于要访问我们这个servlet。
注意:这个路径一定是以/开头的:/a /a/b /a/b/hello


servlet
1.什么是servlet
servlet其实就是java里面一种java类,只不过这种java类有一些特殊的作用,所以我们就叫它servlet
2.servlet的作用
可以让浏览器直接通过一个路径去访问。(一般的java类是做不到这一点的)

3.怎么写一个类,能成为一个servlet
三种方式:
a.实现一个接口:javax.servlet.Servlet
b.继承一个抽象类:javax.servlet.GenericServlet
c.继承一个抽象类javax.servlet.http.HttpServlet
这种是之后一直要用的方法.

注意:Servlet接口中,有五个抽象方法,其实最重要的一个方法是:service(ServletRequestreq,ServletResponse res)
抽象类GenericServlet实现了接口Servlet,但是留了一个抽象方法没有实现,就是上面所提到的service方法,除此之外,GenericServlet里面还增加了一些新的方法.
抽象类HttpServlet,继承了GenericServlet,但是HttpServlet中没有任何抽象方法,除了从父类继承过来的方法之外,里面还有很多新的方法:doXxx方法,另外需要注意的是,HttpServlet里面有俩个service方法,但是俩个方法的参数类型不同.

i.Servlet接口中的service方法.
   因为无论我们使用哪一种方式去写出来的一个servlet类的中,一定会有一个方法叫做service,这个方法是Servlet接口中的定义的,tomcat服务器接收到客户端请求后,帮我们调用servlet中的方法的时候,它只会调用这一个service方法.
   注意这个service方法中参数的类型:
   service(ServletRequestreq,ServletResponse res)

ii.GenericServlet中的俩个init方法
带参数的init(ServletConfig config)方法是从Servlet接口中实现的,还有一个是这个类直接定义的,无参的init()方法.
tomcat服务器创建servlet对象的时候,会帮我们去调用init(ServletConfig config)进行servlet类中的初始化工作,所以如果我们想在servlet类中初始化自己的一些相关数据的话,需要去重写这个init方法。有参数的init方法中调用了无参的init方法,所以将来我们只需要重写这个无参的init方法就可以了。这样我们就不需要再专门对这个init(ServletConfig config)方法中的参数进行处理了。

iii.HttpServlet中的俩个service方法

这个是从Servlet接口中实现的方法.
service(ServletRequest req, ServletResponse res){
    //强转参数类型
    HttpServletRequest request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)res;
    
    //调用新定义的service方法
    service(request,response);
    
}


HttpServlet中新定义的方法
service(HttpServletRequest req, HttpServletResponse resp){
   //拿到当前请求的类型 get/post
   String method = req.getMethod();
   
   //判断请求的方法 然后去调用doXxx方法
       if(method.equals("GET")){
    doGet(req,resp);
   }
   if(method.equals("POST")){
    doPost(req,resp);
   }
   ...
   ..
}

http://ip:port/项目名字/资源路径

http://127.0.0.1:8002/web_test/servlet1

4.servlet的生命周期
    servlet的对象是单例:在web项目整个运行期间,每一个servlet类只会有一个对象存在.默认情况下,这一个对象是在servlet第一次被访问的时候才会创建的,而且之后不管再访问多少次这个servlet,也不会再去创建它的的对象的.(我们可以设置某一个servlet的对象在服务器启动的时候就被创建出来)  
  
     这些操作(方法的调用)都是由服务器来做的:
     1.默认情况下,第一次被访问的时候tomcat创建servlet对象(调用无参构造器)
 2.tomcat调用init(ServletConfig config)方法
      在servlet对象实例化之后,tomcat服务器会立马调用这个方法给servlet的实例进行初始化工作。
 3.客户端访问的时候,tomcat会调用service(ServletRequest req,ServletResponse res)方法
 4.在销毁servlet对象的时候会tomcat调用destroy()方法.


    通过web.xml文件中设置,可以让servlet的对象是在服务器启动的时候被创建出来.
web.xml:
  <servlet>
     <servlet-name>LifeServletTest</servlet-name>
     <servlet-class>com.briup.servlet.LifeServletTest</servlet-class>
     <load-on-startup>1</load-on-startup>
 </servlet>

 加入<load-on-startup>标签,表示这个servlet需要在启动服务器的时候就被创建对象.其中,标签可以要放一个数字,这个数字的大小就决定了多个servlet对象被创建的顺序,数字越小越先创建.(如果我们配置了多个servlet在启动服务器的时候被创建对象的话)



5.servlet的线程安全问题
问题产生的原因:
  1.servlet是单例,一个servlet类只有一个对象在项目运行期间。
  2.web项目项目本身就有多线程的特点,虽然我们在代码中没有写和线程相关的东西,但是这个多线程的特点是由服务器给我们提供出来的,一个客户端发送了一个请求,服务器接收到请求后就会建一个线程去处理这个请求。
所以就有可能出现这样的情况:俩个线程同时去访问同一个servlet对象.
    
如何解决/防止
  1.加锁synchronized
  2.尽量少的定义成员变量
      因为只有成员变量才会产生线程安全的问题(在多个线程访问同一个对象的时候),方法中的局部变量是没有这样的问题的.
      3.其他(实现一些安全性的接口)

6.客户端向服务器发请求并且传参(get/post)
客户端向服务器发送请求可以是get方式也可以是post方式.所以传参也分为get方式下传参和post方式下传参.

1.哪些方式的请求属于get/post方式
    get方式:
       a.浏览器中输入地址(URL)然后回车
       b.超链接
       c.页面中引入的css样式文件
       d.页面中引入的js的文件(javascript)
       e.<img src="image/a.jpg" />
       f.form表单中method="get"
       g.ajax中可以设置异步提交请求的方式为get
       f.其他
       
     post方式:
       a.form表单中method="post"
       b.ajax中可以设置异步提交请求的方式为post
       c.其他

 2.get和post的特点及其区别
    它们各自的特点及其区别主要是体现在所传递的参数上面。

    a.get方式参数
    参数是直接放在要请求url后面的
    例如:
 url?参数名=参数值&参数名=参数值
 要请求的url为:
 http://ip:port/WebTest/firstServlet
 传参:
 .../firstServlet?name=tom
 .../firstServlet?name=tom&age=20

            这种方式传参的特点:
       1.参数直接放在url后面
       2.从浏览器的地址栏里面可以直接看到所传的参数
       3.参数的长度有限制,不能把一个很长的数据通过get方式传参.(与浏览器种类有关)

     b.post方式传参
    参数是放在请求的体部的。
    (浏览器发送的请求可以大致的分为请求头+请求体)

    这种方式传参的特点:
       1.参数放在请求的体部而不是url后面.
       2.浏览器的地址栏中看不到所传的参数.
       3.因为参数不用出现在地址栏里面,所有参数长度是没有限制的.


7.servlet中接收客户端传过来的参数。  
客户端都是以这样的形式传参的:
参数名字=参数值
所有在servlet中我们需要用参数名字来拿到参数值:
String value = request.getParameter("key");
其中key就是参数名字,value是参数值,不管传的值本身是什么类型,servlet中接收到以后只能是字符串类型或者字符串类型数组.
如果客户端用的多选框,这个时候传过来的参数就要用一个字符串类型数组来接收:String[] like = req.getParameterValues("like");
在表单中,参数值就是用户所填写的内容或者是所选的选项的value属性值,参数名字就是每一个input或者其他输入元素中的name属性的值.
例如:
<input type="text" name="username">
参数名字就是name属性的值:username
参数的值就是将来用户所填内容.

在servlet中,不管是get方式提交的时候还是post方式提交的时候,来到servlet里面以后,都是用相同的方式来取得数据。
request.getParameter("key");
request.getParameterValues("key");


8.中文乱码
a.get方式提交数据,servlet拿到后乱码
   需要修改tomcat中的配置文件,然后重新启动tomcat服务器.
   server.xml:在这个文件中找到修改端口号的那个标签,然后加入一个新的属性URIEncoding="UTF-8",或者是写GBK、GB2312
   例如:
   <Connector  connectionTimeout="20000" port="8002" protocol="HTTP/1.1" redirectPort="8443"
   URIEncoding="GBK"/>


b.post方式提交数据,servlet拿到后乱码
   在代码中,我们去接收数据之前,也就是调用getParameter方法之前,需要先转换一下接收数据的编码:
   req.setCharacterEncoding("GBK");
   里面的值可以是GBK、UTF-8、GB2312


注意:其实不管是get方式或者是post方式提交数据,我们最后是在Eclipse/MyEclipse中打印了出来,所以我们最后还要看看工具中是用什么编码显示的我们的数据的.点击一个文件或者项目名字后右键,properties选项中可以看到这个编码.

c.servlet向浏览器返回数据,浏览器显示乱码.
    在代码中,获得输出流之前,我们要先设置输出流是用什么编码把数据写回去的:
    resp.setCharacterEncoding("GBK");
    同时我们还可以通知浏览器我们向它传输的数据是用的什么样的编码:
    resp.setContentType("text/html;charset=GBK");

 注意:在我们使用的浏览器中,也是可以调整编码的设置的,就是我们可以自己选择一种编码来显示当前页面的内容,同时浏览器也会有自己一个默认的显示编码.当浏览器不知道服务器传过来的的数据是用什么编码的时候,浏览器会用默认的编码来显示.



9.servlet中的跳转.
a.服务器内部跳转
   1.跳转到一个页面
   2.跳转到另外一个servlet

page="页面/servlet"
//获得一个跳转对象(服务器内部跳转)
RequestDispatcher rd = req.getRequestDispatcher(page);
//跳转
rd.forward(req,resp);

特点:
1.不管servlet服务器内部跳转多少次,浏览器地址栏中显示的地址都是第一次访问到的servlet的地址
2.服务器内部跳转其实就是把request和response对象进行转发,转发到另外一个服务器内部的一个资源中,如果转发的对象是一个页面,那么就把这个页面返回给浏览器,如果转发的对象是另外一个servlet,那么会调用到这个servlet里面的service方法,然后把之前那个request和response当做传送传进来.
3.在服务器内部跳转的过程中,每一个环节中所用到的request和response对象都是同一个request和response对象.

b.客户端重定向
   1.跳转到一个页面
   2.跳转到另外一个servlet
    
   String page = "页面/servlet";
   resp.sendRedirect(page);

特点:
   1.跳转之后,浏览器中显示的是跳转到的那个资源(页面/servlet)的地址,而不是第一次访问的servlet地址.
   
   2.客服端重定向,其实就是让客户端浏览器重新再发一次新的请求到要跳转的资源。所以在客户端重定向中我们使用的对象是response,因为response这个对象的作用就是向客户端传递数据传递消息用的。
   
   3.在客户端重定向的过程中,每个环节中所用到的request,response对象都是浏览器新发出的。
上一篇 下一篇

猜你喜欢

热点阅读