如何编写一个Servlet

Servlet day2

1.什么是servlet

servlet本身就是一种java类,这种java类可以提供web形式的访问(Java EE 规范)

2.怎么按照JavaEE的规范编写一个servlet

关键字 作用 说明
Servlet 接口 有五个抽象方法
GenericServlet 抽象类 有一个抽象方法
HttpServlet 抽象类 没有抽象方法

HttpServlet-继承->GenericServlet-实现->Servlet接口

所以编写一个servlet,有三种方式

第一种方式:
写一个类去实现接口servlet
最重要的是实现接口中的service方法
这个方法就是我们在访问servlet的时候被tomcat服务器调用的


第二种方式:
写一个类去继承父类GenericServlet
抽象类GenericServlet里面有一个抽象方法service,这个方法是servlet接口中的方法,所以GenericServlet只实现了Servlet接口中的四个抽象方法,还剩下这个service没有实现。同时,GenericServlet类中不但实现了Servlet接口中的init方法,而且还重载了一个无参的init()方法

源代码中两个init方法的实现:

			//tomcat服务器默认调用的是这个init方法
		    @Override
			public void init(ServletConfig config) throws ServletException {
				this.config = config;
				this.init();
			}
			//用户需要重写的是这个init()方法
			public void init() throws ServletException{
				// NOOP by default
			}

第三种方式:
写一个类去继承父类HttpServlet
HttpServlet是一个抽象类,但是没有任何抽象方法
HttpServlet类中自定义了很多doXxxx方法,每一种方法都对应了浏览器发送请求的方法,一般常用的浏览器发请求方式为get和post,这两种方式分别对应了这个类中的doGet方法和doPost方法。
HttpServlet类中,有两个service方法

		//这个service方法Servlet接口中的
		void service(ServletRequest req, ServletResponse res){...}
		
		//这个service是HttpServlet中重载的方法
		void service(HttpServletRequest req, HttpServletResponse resp){...}
		

		源代码中俩个service方法的实现:
		//实现Servlet接口中的service方法
		@Override
		public void service(ServletRequest req, ServletResponse res)
			throws ServletException, IOException {

			HttpServletRequest  request;
			HttpServletResponse response;

			try {
				request = (HttpServletRequest) req;
				response = (HttpServletResponse) res;
			} catch (ClassCastException e) {
				throw new ServletException("non-HTTP request or response");
			}
			//调用重载之后的service方法
			service(request, response);
		}

		
		//HttpServlet类中重载的service方法
		protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

			String method = req.getMethod();

			if (method.equals(METHOD_GET)) {
				long lastModified = getLastModified(req);
				if (lastModified == -1) {
					// servlet doesn't support if-modified-since, no reason
					// to go through further expensive logic
					doGet(req, resp);
				} else {
					long ifModifiedSince;
					try {
						ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
					} catch (IllegalArgumentException iae) {
						// Invalid date header - proceed as if none was set
						ifModifiedSince = -1;
					}
					if (ifModifiedSince < (lastModified / 1000 * 1000)) {
						// If the servlet mod time is later, call doGet()
						// Round down to the nearest second for a proper compare
						// A ifModifiedSince of -1 will always be less
						maybeSetLastModified(resp, lastModified);
						doGet(req, resp);
					} else {
						resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
					}
				}

			} else if (method.equals(METHOD_HEAD)) {
				long lastModified = getLastModified(req);
				maybeSetLastModified(resp, lastModified);
				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 {
				//
				// Note that this means NO servlet supports whatever
				// method was requested, anywhere on this server.
				//

				String errMsg = lStrings.getString("http.method_not_implemented");
				Object[] errArgs = new Object[1];
				errArgs[0] = method;
				errMsg = MessageFormat.format(errMsg, errArgs);

				resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
			}
		}

3.servlet的生命周期

3.1 servlet是单例,在web项目运行期间,一个servlet只会创建一个对象

web项目本身就需要在多线程的环境中运行,tomcat服务器会提供这样的多线程环境,当浏览器发送一个请求,tomcat接收到这个请求之后会开启一个线程去处理这个请求

在这种环境下,由于servlet是单例,所以在servlet中声明的成员变量,就会有线程安全的问题。

所以我们应该尽量少的在servlet中定义成员变量

3.2 默认情况下

servlet对象是在用户第一次访问它的时候,由tomcat服务器来创建的(可以通过配置进行改变)。

3.3 servlet对象创建成功之后

tomcat服务器还会调用servlet里面的init(ServletConfig config),这个有参的init方法会调用无参的init()方法,程序员就可以重写这个无参的init()方法,对创建好的servlet对象进行初始化操作。

3.4 如果用户要访问这个servlet对象

那么tomcat服务器会调用这个servlet对象中的service方法,只不过service方法中又进行了方法的层层调用,最后调用到了我们重写的doGet或者是doPost方法

3.5 当servlet对象被销毁的时候

tomcat服务器会调用servlet里面的destory方法,程序员就可以重写这个方法,表示当对象销毁的时候需要做哪些额外的处理
servlet对象被销毁的情况
1.服务器【正常】关闭的时候
2.服务器重新加载web项目的时候(reloading)

3.6 可以通过修改web.xml文件中的配置,去改变servlet对象创建的时间

只要在标签中,添加一个子标签就可以了
标签表示当前这个servlet需要在启动tomcat服务器期间就被创建出来

标签里面需要放一个正整数,数值的大小可以决定servlet对象被创建的先后顺序,数值越小就越先被创建。(如果有多个servlet对象需要在tomcat启动期间被创建的话)

4.Servlet接口中的方法(共有五个方法)

	//初始化servlet对象的时候被调用
	void 	init(ServletConfig config)

	//销毁servlet对象的时候被调用
	void 	destroy()

	//访问servlet对象的时候被调用
	void 	service(ServletRequest req, ServletResponse res)
	
	//返回servlet相关信息,比如作者、版本、版权等
	//父类中(GenericServlet)默认返回一个空字符串 ""
	//如果需要的话,程序员可以自己重写这个方法
	String 	getServletInfo()

	//返回ServletConfig对象
	ServletConfig 	getServletConfig()

5.ServletConfig接口中的方法(共有四个方法)

ServletConfig接口的实现类对象,表示一个servlet在web.xml文件中的配置信息

	//返回servlet在web.xml文件中所配置的名字
	//也就是这个标签中的值
	String 	getServletName()

	//获得在web.xml中所配置的指定名字的参数值
	//在web.xml可以通过标签给servlet传参
	String 	getInitParameter(String name)

	//获得给当前servlet传的所有参数的名字
	Enumeration 	getInitParameterNames()

	//获得ServletContext类型对象
	//ServletContext是web项目中非常重要的一个类型对象
	ServletContext 	getServletContext()

6.servlet的访问

使用web.xml文件里面的这个标签映射的路径,来访问servlet

6.1 在浏览器的地址栏中,直接输入servlet映射的路径来访问

这时候是get方式的访问,servlet中的doGet方法最终会被调用

6.2 在页面中,可以使用超链接来访问servlet

这时候是get方式的访问,servlet中的doGet方法最终会被调用

6.3 在页面中,可以使用表单发送请求去访问servlet

这时候默认情况下是get方式访问,但是可以通过表单里的属性值进行设置为get或者post方式

6.4 将来还可以使用javascript或者在ajax中发请求访问servlet

这个时候也可以进行设置使用get方式还是post方式进行访问servlet

6.5 其他的情况:

还可以使用标签语言来访问servlet

7.get方式的访问和post方式的访问

get方式访问
浏览器地址栏直接输入地址访问
超链接访问
访问图片
外部js文件的引入
外部css文件的引入
表单提交数据method=“get”
在javascript代码中访问
在ajax中访问
使用jsp相关标签访问


post方式访问
表单提交数据method=“post”
ajax中设置本次请求为post方式


在http协议规范中,定义了四种访问方式(常见的)
get(查) post(改) put(增) delete(删)


http协议规范下的请求格式(分为四部分)
1部分: 请求行
2部分: 请求头部/消息报头
3部分: \r\n
4部分: 请求正文


get方式传参数 参数在uri后面(uri和url的区别)
GET /hello.html?name=tom HTTP1.1
key: value
key: value
key: value

\r\n


post方式传参 参数在请求正文中
POST /hello.html HTTP1.1
key: value
key: value
key: value

\r\n
name=tom


  • get和post的【传参】的安全性
    get方式的参数由于是在地址栏中显示的,所以安全性低一些,post传参的时候参数在请求正文中,相对会安全一些。但是真正重要的数据在传的过程中还会更换协议http–>https,比如在网上支付的过程中

  • get和post在传参过程中参数长度的限制
    get方式传参,参数长度是要看浏览器对地址栏中字符长度的限制,也就是要看浏览器对url地址的长度限制,我们只是把参数放到url后面了。url?参数=值
    post方式参数,参数长度是要看服务器一次性最多能够接受并且处理多少数据

8.在servlet中,接受客户端传的参数

不管客户端是post方式还是get方式传参,只是参数存放的位置在传输过程有所变化,但是对于servlet接收参数来讲,俩种情况都是一样的接收

下面的测试是在这样的传参中进行的
http://127.0.0.1:8989/web_servlet/ParamServlet?name=tom&age=20&like=0&like=1

8.1 接收单一的值(一个参数名对应一个值)

		String name = request.getParameter("name");
		String age = request.getParameter("age");
		System.out.println(name);
		System.out.println(age);

8.2 一个参数名对应多个值(比如多选框)

		String[] like = request.getParameterValues("like");
		System.out.println(Arrays.toString(like));

8.3 获得本次传参中的所有参数名

		Enumeration<String> names = request.getParameterNames();
		while(names.hasMoreElements()){
			String str = names.nextElement();
			System.out.println(str);
		}
	打印结果:
	name
	age
	like

8.4 获得本次传参中的所有参数及对应的值

		Map<String, String[]> map = request.getParameterMap();
		for(String key:map.keySet()){
			System.out.println(key+" : "+Arrays.toString(map.get(key)));
		}
	打印结果:
	name : [tom]
	age  : [20]
	like : [0, 1]

9.客户端传参过程中,出现中文乱码

9.1 get方式传参,中文乱码

需要在tomcat服务器中server.xml文件中进行配置

中加入新的属性URIEncoding="XXX"
	

9.2 post方式传参,中文乱码

在使用request获取参数【之前】,先把request中的编码进行设置

		request.setCharacterEncoding("UTF-8");
		String name = request.getParameter("name");
		System.out.println(name);

9.3 servlet中使用io流写数据到浏览器,浏览器里面显示中文乱码

http协议规范中响应的格式为:
1部分 响应状态行
2部分 响应头部/消息报头
3部分 \r\n
4部分 响应正文


如果响应头部信息中没有设置编码,那么浏览器会默认使用简体中文(GBK)来解析响应中的内容


所以在使用io流之前,需要设置一下response中的编码,同时还要告诉浏览器本次响应内容的编码是什么
//设置response中的编码为UTF-8
response.setCharacterEncoding(“UTF-8”);
//设置响应头部,告诉浏览器响应内容编码为utf-8
response.setContentType(“text/html;charset=utf-8”);

9.4 Unicode(字符集)和UTF-8(编码规则)

Unicode符号范围 | UTF-8编码方式
十六进制 二进制
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

你可能感兴趣的:(Servlet学习)