Tomcat_Servlet

系统架构分类
-C/S    -B/S

-C/S:Client/Server
	优点:速度快,大部分数据已集成到客户端软件中,只需要从服务器上传送少量数据即可。
		速度很快,用户体验好。
		大部分的数据集成到了客户端,相对安全。
		C/S的客户端界面可以非常炫
	缺点:升级需要每个客户端都升级,升级麻烦
		需要安装特定的客户端软件,才能访问服务器
		
-B/S:Browser/Server
	优点:不需要安装特定的客户端软件,只要有浏览器就行,客户在这一方面体验不错,
		 升级只需升级服务器端,方便。
	缺点:所有数据全部集成在服务器端,一旦发生不可抗力,数据丢失,相对来说不安全
		 速度慢,用户体验差
		 
娱乐系统适合使用C/S架构,企业内部的系统适合使用B/S架构。		 
Tomcat
Tomcat配置:
    配置bin目录和CATALINA_HOME变量,目的是在命令窗口直接执行服务器命令
        配置bin目录,路径是到bin路径下
        配置CATALINA_HOME:路径是到根路径下
        
Tomcat服务器目录结构:
    1. bin:
       bin目录用来存放tomcat的命令,主要有两大类
        一类是以.sh结尾的(linux命令),另一类是以.bat结尾的(windows命令)。
       - startup 用来启动tomcat
       - shutdown 用来关闭tomcat

    2. conf:
       conf目录主要是用来存放tomcat的一些配置文件。
       - server.xml可以设置端口号、设置域名或IP、默认加载的项目、请求编码
       - web.xml可以设置tomcat支持的文件类型
       - context.xml可以用来配置数据源之类的
       - tomcat-users.xml用来配置管理tomcat的用户与权限
       - 在Catalina目录下可以设置默认加载的项目

    3. lib:
       lib目录主要用来存放tomcat运行需要加载的jar包。

    4. logs:
       logs目录用来存放tomcat在运行过程中产生的日志文件,非常重要的是在控制台输出的日志。
           (清空不会对tomcat运行带来影响)
       在windows环境中,控制台的输出日志在catalina.xxxx-xx-xx.log文件中
       在linux环境中,控制台的输出日志在catalina.out文件中

    5. temp:
       temp目录用户存放tomcat在运行过程中产生的临时文件。(清空不会对tomcat运行带来影响)

    6. webapps:
       webapps目录用来存放应用程序,当tomcat启动时会去加载webapps目录下的应用程序。
       可以以文件夹、war包、jar包的形式发布应用。
       当然,也可以把应用程序放置在磁盘的任意位置,在配置文件中映射好就行。

    7. work:
       work目录用来存放tomcat在运行时的编译后文件,例如JSP编译后的文件。
       清空work目录,然后重启tomcat,可以达到清除缓存的作用。
第一个WebApp
在html中的超链接,完整的可以写成:<a href="http://localhost:8080/app01/login.html">Login</a>

为了代码的更加通用,可以直接从部署的项目名开始写,前面的IP地址和端口号可以省略,但要注意省略之后是以“/”开头    
Servlet
Serv表示服务器端,let表示小程序
就是sum公司制定的Web服务器和Web服务器端的java小程序之间的接口,其中有五个方法需要重写:
    void destroy();
    ServletConfig getServletConfig();
    String getServletInfo();
    void init(ServletConfig config);
    void service(ServletRequest request, ServletResponse response);
第一个带有Servlet的WebApp
WebAp的目录结构:
    最重要的:WEB-INFO文件夹、以及html文件夹、css文件夹、js文件夹等文件夹
    WEB-INF文件夹里面有:
		classes文件夹--->存放字节码文件
		lib文件夹------->存放程序运行所需要的库(如数据库驱动);
		web.xml--------->配置文件,写的是请求路径与绑定的从servlet文件(Java文件)
            
Tomcat服务器的lib和webapp的lib目录:
    Tomcat服务器目录的lib是Tomcat的classpath,是全局的
    每一个webapp也有一个lib,相当于是项目自己的classpath,是局部的
            
web.xml文件编写:
            
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_4_0.xsd"
	version="4.0">

    <servlet>
    	<servlet-name>ThisIsHelloServlet</servlet-name>
    	<servlet-class>cn.qkmango.HelloServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>ThisIsHelloServlet</servlet-name>
        <url-pattern>/hello/servlet/test</url-pattern>
        <url-pattern>/hello/servlet</url-pattern>
        <!--路径随意编写,但是必须以 “/”开始,这个路径是虚拟路径,
            这个路径是cn.qkmango.HelloServlet.class文件的代号,
            用户只要访问这个路径,就会执行cn.qkmango.HelloServlet.class文件
            对应的url-pattern可以有多个
            注意,url-pattern不需要以项目名开头,但是超链接需要以项目名开头-->
    </servlet-mapping>
</web-app>       

          
web.xml文件主要配置请求路径和Servlet类名之间的绑定关系
web.xml文件在Tomcat服务器启动阶段被解析
web.xml文件解析失败,会导致webapp启动失败
web.xml文件中的标签不能随意编写
web.xml文件中的标签也是sun公司指定的Servlet规范 
一个webapp只有一个web.xml  
将响应结果输出到浏览器中
将内容输出到浏览器的三个步骤:
    1. 解决中文乱码问题,设置内容类型和字符集
        因为writer是从servletResponse获取的,所以在获取之前进行设置
        servletResponse.setContentType("text/html;charset=UTF-8");

    2. 获取流对象,直接指向浏览器客户端
        PrintWriter writer = servletResponse.getWriter();

    3. 将内容输出到浏览器
        writer.print();

/* WelcomeServlet类 */
import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;//标准输出流,不需要关闭
public class WelcomeServlet implements Servlet {//实现Servlet要重写它的5个方法
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {}

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        
        servletResponse.setContentType("text/html;charset=UTF-8");
        /**
         * 将信息输出到浏览器上
         * 将HTML字符输出到浏览器上,浏览器解释执行
         * 获取流对象,直接指向浏览器客户端
         */
        PrintWriter writer = servletResponse.getWriter();

        writer.print("<html>" +
                "<head><title>welcome欢迎</title></head>" +
                "<body><h1>welcome Page欢迎页面</h1></body>" +
                "</html>");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {}
}
编写JDBC连接到数据库
	注意把jar包导入到对应的位置,最好是能够检查一下,如果使用了数据库连接池,那么同时也要导相应的jar包,还有数据库的驱动jar包。
	Eclipse中项目默认是在:					           	             F:\JAVA\EclipseWorkSpace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps中但是可以更改默认配置。     
Servlet生命周期
生命周期?
    一个程序从创立到销毁经历的所有过程
    
Servlet对象的生命周期是谁来管理的?
    Servlet对象的生命周期,包括Servlet对象方法的调用,javaweb程序员是无权干涉的。
    Servlet对象从最初创建到方法的调用及对象的销毁,整个过程都是web容器(Web Container)来管理的。
    
默认情况下,Servlet对象在web服务器启动阶段不会被实例化。若希望在web服务器启动阶段实例化Servlet对象:
    需要在配置文件servlet中加上‘<load-on-startup>自然数<load-on-startup>’,自然数越小,优先级越高)
    
描述Servlet对象生命周期*****
    1、用户在地址栏输入URL:http://localhost:8080/adhhqk/uqidqk
    2、web容器截取请求路径:/adhhqk/uqidqk
    3、web容器在上下文中找请求路径/adhhqk/uqidqk对应的Servlet对象
    4、若没有找到对应的Servlet对象
        4.1、通过web.xml文件中相关的配置信息,得到请求路径/uqidqk对应的Servlet完整类名
        4.2、通过反射机制,调用Servlet类的无参数构造方法完成Servlet对象的实例化
        4.3、web容器调用Servlet对象的init方法完成初始化操作
        4.4、web容器调用Servlet对象的service方法提供服务
    5、若找到对应的Servlet对象
        5.1、web容器直接调用Servlet对象的service方法提供服务
    6、web容器关闭的时候/webapp重新部署的时候/该Servlet对象长时间没有用户再次访问的时候,web容器会将该Servlet对象销毁,在销毁该对象之前,web容器会调用Servlet对象的destroy方法,完成销毁之前的准备。
        
总结:
    Servlet类的构造方法只执行一次
    Servlet对象的init方法只执行一次
    Servlet对象的service方法,只要有用户请求一次,则执行一次
    Servlet对象的destroy方法只执行一次

注意:
	init方法执行的时候,Servlet对象已经创建好了。
	destroy方法执行的时候,Servlet对象还没有被销毁,处于即将销毁。
        
Servlet对象是单例,但是不符合单例模式,只能称为伪单例。真单例的构造方法是私有化的。
        
	Tomcat服务器是支持多线程的,所以Servlet对象在单实例多线程的环境下运行的。那么Servlet对象中若有实例变量,并且实例变量涉及到修改操作,那么这个Servlet对象一定会存在线程安全问题,不建议在Servlet对象中使用实例变量,尽量使用局部变量。
        
        
Servlet对象实例化之后存储到哪里了?
	大多数的Web容器都是将该Servlet对象以及对应的url-pattern存储Map集合中了,在web容器中有这样一个Map集合
	Map<String, Servlet>
        
        key             value
        --------------------------------------
        /login          LoginServlet对象的引用
        /delete         DeleteServlet对象的引用
        /insert         InsertServlet对象的引用
        
服务器启动阶段解析的web.xml文件,做了什么?        
	在web容器中有这样一个集合:Map<String, String>
        key             		value
        ---------------------------------------------------------
        /login          login对应的全类名
        /delete         delete对应的全类名
        /insert         insert对应的全类名
        
        实际上,服务器启动时就会解析web.xml文件,并且将解析的数据存放在Map集合中,当在浏览器中输入请求的路径时,web容器在容器里去找请求路径对应的Servlet对象,如果没有找到,**实际上不是去web.xml文件中找此路径对应的完整类名,而是去此Map集合中查找
        
Servlet接口中的方法写什么代码?何时使用?
        
	1. 无参构造方法【以后就不需要考虑构造方法了,尽量别动构造方法】
        
	2. init():
       无参构造方法和`init()`,两个方法执行时间几乎是相同的,都只执行一次
       若系统要求对象在创建时刻执行一段特殊的程序,这段程序尽量写到init()方法中
       为什么不建议将代码写到构造法中呢?
           存在风险!当程序员编写构造方法的时候,可能会导致无参构造方法不存在
       Servlet中的`init()`方法是SUN公司为程序员专门提供的一个初始化时刻,若希望初始化时刻执行一段程序,这个程序可以编写在`inti()`方法中,将来会被自动调用

    3. service()
       这个方法是必然重写的,因为这个方法需要完成业务逻辑的处理,请求的处理,以及完成响应
        
    4. destroy()
       这个方法是为程序员提供的一个特殊时刻,这个特殊时刻被成为对象销毁时刻;若希望在销毁时刻执行一段特殊代码,需要将这段代码写到`destroy()`方法中,会被自动调用        
ServletConfig接口
1. 【作为了解】Apache Tomcat服务器实现了Servlet规范,Tomcat服务器写了一个ServletConfig接口的实现类,实现类的完整类名是`org.apache.catalina.core.StandardWrapperFacade`

2. Javaweb程序员在编程的时候,一直是面向ServletConfig接口去完成调用的,不需要关心具体的实现类,只需要学习ServletConfig接口有哪些可以使用的方法。
   - webapp放到Tomcat服务器中,ServletConfig的实现类是:`org.apache.catalina.core.StandardWrapperFacade`
   - webapp放到JBOSS服务器中,ServletConfig的实现类可能是另外一个类名了

3. 怎么理解Tomcat服务器?
    Tomcat服务器是一个实现了Servlet规范和JSP规范的容器
    
ServletConfig到底是什么?
    ServletConfig是一个Servlet对象的配置信息对象,ServletConfig对象中封装了一个Servlet对象的配置信息
    Servlet对象的配置信息在web.xml文件中
    一个Servlet对象对应一个ServletConfig对象对象,100个Servlet对象对应100个ServletConfig对象
    
如何在`service()`方法中使用`init()`方法中的`servletConfig`参数对象 
	在`init()`方法中完成:局部变量servletConfig赋值给实例变量servletConfig:this.config = config;
	在`getServletConfig()`,提供公开的get方法,目的是供子类使用,只需要修改return返回值即可:return config;

ServletConfig接口中的方法
    String `getInitParameter(String name)` 
    	通过name,获取初始化参数name对应的value
    Enumeration `getInitParameterNames()` 
    	获取初始化参数的name集合。遍历用hasmoreElements();
    String `getServletName()` 
    	获取servletName,`<servlet-name>servletName</servlet-name>`
    ServletContext `getServletContext()` 
    	获取ServletContext【Servlet上下文】对象
    
`<init-param>`标签,初始化参数
     `<init-param>`标签是初始化参数,定义在`<servlet>`标签中
     `<init-param>`标签内还有`<param-name>`表示key,`<param-value>`表示value
     `<init-param>`定义的参数属于某一个 Servlet
    String value = servletConfig.getInitParameter(name)获取的就是`<init-param>`中的参数
    这些信息封装在ServletConfig对象中    
ServletContext接口
1. `javax.servlet.ServletContext`接口,Servlet规范

2. Tomcat服务器对ServletContext接口的实现类完整类名是:`org.apache.catalina.core.ApplicationContextFacade`
   javaweb程序员只需要面向ServletContext接口调用方法即可,不需要关心Tomcat具体的实现
    
ServletContext到底是什么?什么时候被创建?什么时候被销毁?创建几个?    
    - ServletContext被译为:Servlet上下文
    - 一个webapp只有一个web.xml文件,web.xml文件服务器启动阶段被解析
    - 一个webapp只有一个ServletContext对象,ServletContext对象在服务器启动阶段被实例化
    - ServletContext在服务器关闭的时候被销毁
    - ServletContext对应的是web.xml文件,是web.xml文件的代表
    - ServletContext是所有Servlet对象四周环境的代表,被所有Servlet共享
    - 所有用户若想共享同一个数据,可以将数据放到ServletContext对象中(写到web.xml文件中,或后期通过方法添加)
    - 一般放到ServletContext对象中的数据不建议涉及到修改操作的,以为ServletContext是多线程共享的一个对象,修改的时候会存在线程安全问题 
    
ServletContext接口中有哪些常用方法    
    - void `setAttribute(String name, Object object)` 
    	向ServletContext中添加数据
    - Object `getAttribute(String name)` 
    	从ServletContext中获取数据
    - void `removeAttribute(String name)` 
    	从ServletContext中移除数据
    - String `getInitParameter(String name)` 
    	从ServletContext中获取name所对应的value初始化参数(\<context-param>标签中)
    - Enumeration `getInitParameterNames()`
    	从ServletContext中获取name所对应的value初始化参数(\<context-param>标签中),遍历用hasmoreElements()
    - String `getRealPath(String path)` 
    	获取文件绝对路径    
    
ServletContext范围可以完成跨用户传递数据
        `<context-param>`上下文参数,定义的参数属于全局,所有Servlet共享
             `<param-name>`表示参数的name(key)`</param-name>`
             `<param-value>`name所对应的value`</param-value>`
        `<context-param>`
- 这些参数信息封装在ServletContext对象中
    	ServletContext application = config.getServletContext();
		application.getRealPath("/资源路径");
Servlet、ServletConfig、ServletContext之间的关系
- 一个Servlet对应一个ServletConfig对象
- 所有的Servlet共享一个ServletContext对象
欢迎页面
欢迎页面是怎么设置的?
	假设在webapp/html目录下创建welcome.html,想让welcome.html作为整个webapp的欢迎页面,应该在web.xml文件中添加如下标签
	欢迎页面可以设置多个,越靠上越优先,当前面的欢迎页面找不到时才使用后面的欢迎页面
    <!--将welcome.html页面作为欢迎页面-->
    <!--注意开头没有“/”-->
    <welcome-file-list>
        <welcome-file>html/welcome.html</welcome-file>
        <welcome-file>welcome2.html</welcome-file>
    </welcome-file-list>
欢迎页面可以是任何一种web资源
    欢迎页面不仅可以是html文件,也可以时任何一种web资源,如Servlet

欢迎页面有全局配置和局部配置
    全局配置:`CATALINA_HOME/conf/web.xml`
    局部配置:`CATALINA_HOME/webapps/webapp/WEB-INF/web.xml`
    若有局部配置,优先使用局部配置(就近原则)
	若在web目录中有index.html、index.htm、index.jsp文件,这些都是默认的欢迎页面,都在全局配置中已经配置过了,即全局配置中,默认以这些文件为欢迎页面
常见错误代码
-404 Not Found 资源未找到,一般是路径写错。
-500 Server Inner Error 服务器内部错误,一般都是服务器Java程序出现异常
    
404和500是HTTP协议状态码,是W3C制定的,正常响应的HTTP协议状态码是200    
    
可以在web.xml中添加错误页面,出现错误跳转到指定页面。
    <error-page>
        <error-code>404</error-code>   
        <location>/errorPage/404.html</location>
	</error-page>	
GenericServlet适配器
缺省适配器
    目前我们所有的Servlet类直接实现了javax.servlet.Servlet接口,但是这个接口中有很多方法但是可能方法不需要。导致直接实现Servlet接口的代码丑陋,所以有必要在中间添加一个适配器,以后所有的Servlet类不再直接实现Servlet接口,而而是去继承适配器
    适配器可以让代码优雅之外,我们还可以在适配器中提供大量的方法,子类继承之后,可以在子类中直接使用,方便编程
 
自定义GenericServlet类(适配器):    
    问题:为了让适配器类中`init(ServletConfig)`中的代码生效,而被final修饰限制不被重写,那么怎么在初始化时刻执行一段代码呢?
    解决:`init()`方法为`init(ServletConfig)`同名的重载方法,原本的`init(ServletConfig)`方法为了使其中的代码不被覆盖重写而失效,所以添加了`final`修饰,但是使得`init(ServletConfig)`无法重写而过于局限,所以我们扩展一个同名的`init()`方法供程序员重写,`init()`会被`init(ServletConfig)`调用,这样我们只需要重写`init()`即可,若在Servlet初始化时刻需要执行一段特殊的代码,建议重写此无参数的`init()`方法   
    
SUN提供的GenericServlet类(适配器):
	SUN公司已经为我们准备了官方的GenericServlet类-->`javax.servlet.GenericServlet`
HTTP协议
什么是HTTP协议?
    - 超文本传输协议
    - 浏览器和服务器之间的一种通讯协议
    - 该协议时W3C负责制定的,其本质上就是数据传送格式。浏览器和服务器都必须按照这种格式接收与发送数据
    
1.01.1版本区别
    1.0在应对有图片的资源的时候需要跑两趟,而1.1只需要一趟
    
状态码:
    1xx:请求已到达服务器,但未完成,需要再次请求
    2xx:请求已到达服务器,并且已完成
    3xx:服务器内部资源重定向
    4xx:资源找不到
    5xx:服务器内部异常,代码异常
	手动设置状态码:
    只显示状态码:response.setStatus(xxxx);
    设置状态码的同时加上提示语句:response.sendError(xxx,"提示");

HTTP协议包括几部分?
    请求协议:
        - 请求行:请求方式 URI 协议版本号 `POST /webapp10/login HTTP/1.1`
        - 请求报头
        - 空白行
        - 请求体
    
	响应协议:
    	- 状态行:协议版本号 状态码 描述信息
    	- 响应报头
    	- 空白行
    	- 响应体
    空白行是专门用来分隔消息报头和请求体的
	响应协议中的状态码:404-资源未找到  500-服务器内部错误 200-响应成功,正常结束

响应报头常见使用:
    使用Location进行跳转,需要先设置服务器状态码为302
    	response.setStatus(302);--->response.setHeader("Location","跳转网址");
	使用refresh进行延时跳转
        response.setHeader("Refresh","时间;跳转网址");
	使用Content-Type显示服务器图片(注意图片放在src下)
        response.setHeader("Content-Type","jpg/image/...");
		Web中读取文件使用类加载器:this.getClass().getClassLoader().getResourceAsStream("文件");
    	web中输出流使用:ServletOutputStream out = response.getOutputStream();
		开始边读边写
    使用Content-Disposition下载内容
         response.setHeader("Content-Disposition","attachment;filename=文件名");然后流操作
    
	注意:
            ServletOutputStream out = response.getOutputStream();字节流
            PrintWriter out = response.getWriter();字符流
            注意:这两个流不能同时使用。

    
get请求和post请求:
    
什么情况下浏览器发送的请求是GET请求,什么情况下浏览器发送的请求是POST请求?
    只有当使用表单form,并且method属性设置为"post",才是POST请求方式,其余剩下的所有请求都是GET请求
    
GET请求和POST请求有什么区别?
    GET请求在请求行上提交数据,格式`uri?name=value&name=value`,这种提交方式最终提交的数据会显示在浏览器地址栏上
    POST请求在请求体中提交数据,相对安全,提交格式`name=value&name=value`,这种提交方式最终不会显示在浏览器地址栏上
    GET请求在请求行上提交数据,所以GET请求提交的数据长度有限制
    POST请求在请求体中提交数据,所以POST请求提交的数据没有长度限制【POST可以提价大数据】
    GET请求只能提交字符串数据,POST请求可以提交任何类型的数据,包括视频...,所以文件上传必须使用POST请求
    GET请求最终的结果,会被浏览器缓存收纳,而POST不会被缓存收纳
    
GET请求和POST请求应该如何选择?
    - 有敏感数据 POST
    - 传送的数据不是普通字符串 POST
    - 传送的数据非常多 POST
    - 这个请求是为了修改服务器端资源 POST
    
    - GET请求多数情况下是从服务器中读取资源,这个读取的资源在短时间内不会发送变化,所以GET请求最终的结果会被浏览器缓存起来
	- POST请求是为了修改服务器端的资源,而每一次修改结果都是不同的,最终结果没有必要被浏览器缓存    
    
	浏览器将资源缓存后,缓存的资源是和某个特定的路径绑定在一起的,只要浏览器再发送这个相同的请求路径,这个时候浏览器就会去缓存中获取资源,不再访问服务器,以这种方式降低服务器的压力,提高用户体验。
 
但是有的时候我们并不希望走缓存,希望每一次重新访问服务器,可以在请求路径后面添加时间戳,例如:`http://ip:port/oa/system/logout?timetamp=1234564635423`    怎么获取毫秒值:new Date().getTime();
HttpServlet
SUN公司为我们提供了一个类来解决判断前后端请求方式是否一致的类:
	`javax.servlet.http.HttpServlet`
	
我们写的XxxServlet继承HttpServlet后,后端需要的是什么请求,那么我们就重写对应的`doPost()`/`doGet()`方法

`doPost()`/`doGet()`方法内就是我们的业务代码,`doXXX()`可以看作`main()`方法

代码不在`service()`内编写了,不需要重写`service()`方法

HttpServlet中重载的两个`service()`方法并不需要也没有理由去重写这两个方法

当浏览器发送的请求方式和后台处理方式不同时,会出现一个错误,代号:405	
    
自定义的HttpServlet(帮助理解原理)    
public class HttpServlet extends GenericServlet {
    /**
     *  此方法为原始service()方法,方法内将ServletRequest、ServletResponse强转为带有http的接口
     *  然后调用重载的service(HttpServletRequest, HttpServletResponse)方法
     *  所以此方法我们无需进行重写
     */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        service(request,response);
    }

    /**
     * 此方法获取请求方式后进行判断,
     * 如果是GET请求就执行doGet()
     * 如果是POST请求就执行doPost()
     * 此方法没有理由重写,只需要将业务代码写在doGet()或doPost()方法中即可
     */
    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String method = request.getMethod();
        if("POST".equals(method)) {
            doPost(request, response);
        } else if("GET".equals(method)) {
            doGet(request, response);
        }
    }

    /**
     * 我们需要什么请求时,子类继承此父类就应当重写对应的doGet()或者doPost()方法之一
     * 在doGet()或者doPost()方法内写业务代码,即将原来的service()内的业务代码写到doXXX()中
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().print("应当发送GET请求");
        throw new RuntimeException("应当发送GET请求");
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().print("应当发送POST请求");
        throw new RuntimeException("应当发送POST请求");
    }
}
此时编写了一个方法继承了自定义的HttpServlet
- 假设前端发送的是POST请求
      `service(ServletRequest, ServletResponse)` 将两个参数强转为带有Http的接口,之后执行
      `service(HttpServletRequest, HttpServletResponse) `获取请求方式POST并通过判断执行重写的doPost()方法
      `doPost(HttpServletRequest, HttpServletResponse)` 执行业务代码
- 假设前端发送的是GET请求
      `service(ServletRequest, ServletResponse)` 将两个参数强转为带有Http的接口,之后执行
      `service(HttpServletRequest, HttpServletResponse)`获取请求方式GET并通过判断执行未被重写的doGet()方法
      `doGet()` 报错,将错误信息输出到控制台和前端页面
模版方法设计模式(templateMethod)
模版方法,定义核心算法骨架,具体的实现步骤延迟到子类中完成
public abstract class Person {
    /**
     * templateMethod是一个模版方法,定义核心算法骨架,具体的实现步骤延迟到子类中完成
     * 算法为了受到保护,所以模版方法一般都使用final修饰,不被重写
     * 核心算法骨架不需要每一次在具体的类中编写了,这个核心算法只在模版方法中编写一次
     * 算法步骤改变,只要更改模版就可以,同时也避免了算法在每一个具体的类中编写而冗余
     */
    public final void templateMethod() {
        //核心算法骨架
        do1();
        do2();
        do3();
    }
    /**
     * 这就是具体的实现,这个具体的步骤可以延迟到子类中完成(经子类继承实现)
     * 这个方法通常是抽象方法
     */
    protected abstract void do1();
    protected abstract void do2();
    protected abstract void do3();
}    

模版方法设计模式属于行为行设计模式
模版方法有一个特点:`doXXX()`

模板方法设计模式的主要作用:
    1. 核心算法得到保护
    2. 核心算法得到复用
    3. 在不改变算法的前提下,却可以重新定义算法步骤的具体实现

模板方法设计模式的经典例子:
        - Servlet规范中的HttpServlet
        - HttpServlet就是一个非常典型的模板方法设计模式
        - HttpServlet是一个模板类
        - 其中的service(HttpServletRequest, HttpServletResponse)方法是典型的模板方法,该方法中定义了核心算法骨架,doGet()doPost()......具体的实现细节延迟到子类中完成
MVC架构
生活中的三层架构:(服务员,厨师,采购)
    优点:各司其职,互不干扰,工作效率高,任意环节出现问题有相应的责任人,与他人无关。
    缺点:员工越多,成本越高。
    
软件中的三层架构:(表示层,业务逻辑层,数据访问层)
    表示层:与用户交流的页面,相当于服务员
    业务逻辑层:实现逻辑控制,相当于厨师
    数据访问层:与数据库交互,相当于采购
    优点:
        1)结构清晰,降低耦合
        2)可维护性高,可扩展性高
        3)有利于团队开发
        4)适应需求变化
    缺点:
        1)代码量增加
        2)降低系统性能

M:model     V:view        C:controller

MVC与三层架构的关系
    表示层:view,controller
    业务逻辑层:controller
    数据访问层:model

使用MCV搭建项目目录
    表示层:HTML或者JSP放到WebContent中,com.ujiuye.servlet
    业务逻辑层:com.ujiuye.servlet,com.ujiuye.service
    数据访问层:com.ujiuye.dao
    实体类:com.ujiuye.entity
    工具类:com.ujiuye.util
    测试类:com.ujiuye.test
HttpServletRequest接口
1. HttpServletRequest是一个接口,Servlet规范中重要的接口之一

2. 继承关系:public interface HttpServletRequest extends ServletRequest

3. HttpServletRequest接口的实现类时Web容器负责的,Tomcat服务器有自己的实现。所以程序员还是只需要面向HttpServletRequest接口调用方法即可,不需要关心具体的实现类

4. HttpServletRequest这个对象中封装了哪些信息?
   封装了HTTP请求协议的全部内容:
   - 请求方式
   - URI
   - 协议版本号
   - 表单提交的数据
     ......
5. HttpServletRequest一般对象的名字叫做:request;

   HttpServletRequest对象代表一次请求,一次请求执行一次service()方法,对应一个request对象,100个请求对应100个request对象,所以request对象的生命周期是短暂的;

   什么是一次请求?到目前为止,我们可以这样理解一次请求:在网页上点击超链接,到最终网页停下来,这就是一次完整的请求;(后面学习重定向,浏览器会自动跳转到其他地址,会重新发送新的请求,这句话就不正确了)

6. 获取用户信息,表单提交的这些数据被自动封装在request对象中了
   表单数据是这样的格式提交的,POST请求,在请求体中提交,数据格式: 
    username=admin&password=123&sex=boy&interest=sport&interest=music&grade=gz&introduce=student
    表单提交的数据会自动封装到request对象中,request对象中有一个Map集合,存储这些数据:
    
    Map<String, String[]>
        key          value(value是一维数组)
        -------------------------------
        username     {"admin"}
        password     {"123"}
        sex          {"boy"}
        interest     {"sport","music"}
        grade        {"gz"}
        introduce    {"IAmAStudent"}

HttpServletRequest中常用的方法:
    /*获取浏览器提交的数据*/
    String getParameter(String name) 获取key对应的一维数组的首元素
    Map getParameterMap() 获取request对象中的Map集合
    Enumeration getParameterNames() 获取所有的Map集合中所有的key
    String[] getParameterValues(String name) 返回String数组,数组包含key对应的多个value值
    
    /*获取路径、URL、URI、IP*/
    String getContextPath() 获取上下文路径(web项目根路径)
    String getMethod() 获取浏览器请求方式
    String getRequestURI() 获取请求的URI
    StringBuffer getRequestURL() 获取请求的URL
    String getServletPath() 获取请求的ServletPath,即servlet对应的请求路径
    String getRemoteAddr() 获取客户端IP地址
    
    /*从一次请求对应的HttpServletRequest对象范围中增删查数据*/
    Object getAttribute(String name) 从此次请求对应的request对象范围中获取数据
    void setAttribute(String name, Object o) 从此次请求对应的request对象范围中存储数据
    void removeAttribute(String name) 从此次请求对应的request对象范围中删除数据
    
    /*请求转发器*/
    RequestDispatcher getRequestDispatcher(String path) 获取请求转发器
	请求转发:
    	1. 获取请求转发器对象、2. 调用请求转发器的`forward()`方法即可完成转发
    			/*
                /a路径对应AServlet,/b路径对应BServlet,

                通过request对象的getRequestDispatcher方法获取请求转发器对象,
                然后调用请求转发器对象的forward方法进行转发

                以下代码是从AServlet转发到BServlet
                */

                //获取请求转发器,以下转发器指向了BServlet,调用请求转发器的forward()
                RequestDispatcher requestDispatcher = request.getRequestDispatcher("/b");
                requestDispatcher.forward(request,response);
				//合并:request.getRequestDispatcher("uri").forward(request,response);
				

    /*编码*/
    void setCharacterEncoding(String env) 覆盖此请求正文中使用的字符编码的名称

    /**/
    HttpSession getSession() 返回与此请求关联的当前会话,或者如果该请求没有会话,则创建一个。
    Cookie[] getCookies() 返回一个数组,其中包含Cookie 客户端与此请求一起发送的所有对象。
   
关于范围对象的选择:  
    ServletContext 应用范围极大,可以跨用户传递数据,整个webapp只有一个ServletContext对象
    ServletRequest请求范围小,只能在同一个请求中传递数据【跨Servlet传递数据,需要使用请求转发技术】
    优先选择使用ServletRequest传递数据  
        
文件上传:就是复制一份源文件到指定的位置去:
    步骤:
        1、表单的method属性的值必须是post,在表单上加上enctype,值为multipart/form-data
        2、在Servlet上加上@MultipartConfig
        3、写代码:
        	//先获取上传的文件对象
        	Part part = request.getPart("表单file中的name");
			//找到上传的文件的文件名和扩展名
			String header = part.getHeader("Content-Disposition");
			//获取文件名
			String fileName = header.substring(header.indexOf("filename")+10,header.length()-1)
             //指定上传位置
             String path = "位置";
			//判断该文件夹是否存在,如果不存在,则创建夹	
			File file = new File(path);
			if(!file.existe()){file.mkdir}
			//防止文件重名,可以使用UUID工具类生成随机32位随机字符串
			part.write(path+"/"+UUID.randomUUID()+fileName);
项目中出现乱码问题
数据保存过程中的乱码:
	- 数据保存到数据库表中的时候,数据出现乱码
          - 导致数据保存过程中的乱码包括以下两种情况:
          - 前一种情况:在保存之前,数据本身就是乱码,保存到数据库表中的时候一定是乱码
          - 第二种情况:保存之前,数据不是乱码,但是由于数据库本身数据库不支持简体中文,保存之后出现乱码
          
数据展示过程中的乱码:
	最终显示到网页上的数据出现中文乱码
		第一种情况:经过执行Java程序之后,Java程序负责向浏览器响应的时候,中文乱码
            解决:Java程序中设置响应的内容类型,以及对应的字符字符集
                response.setContentType("text/html;charset=UTF-8");
		第二种情况:没有经过Java程序,直接访问的是html页面
        	解决:在html文件中使用<meta content="text/html;charset=utf-8">
        	或者<meta charset="utf-8">
	
数据传递过程中的乱码:
	通用方法:
		//获取乱码字符
        String dname = request.getParameter("name");
        //将乱码字符通过错误的ISO-8859-1编码方式重新还原回去
        byte[] bytes = dname.getBytes("ISO-8859-1");
        //再通过正确的编码方式进行解码
        value = new String(bytes, "UTF-8");

	仅支持POST请求:
        //设置字符编码方式
        request.setCharacterEncoding("UTF-8");

	仅支持GET:
        修改CATALINA_HOME/conf/server.xml文件,
        加上URLEncoding="UTF-8"属性,设置请求行上的编码方式,解决GET请求乱码
        	<Connector port="8080" 
            protocol="HTTP/1.1"
            connectionTimeout="20000"
            redirectPort="8443" 
            URLEncoding="UTF-8"/>
            //Connector里面还可以编写哪些属性:帮助文档:CATALINA_HOME/webapps/docs/config/http.html
            //eg:port-端口号;maxThreads-最高支持线程数量默认200;URIEncoding-请求行上的编码方式
            
URLencode:是将字符通过某种字符集进行编码后,再使用百分号编码.如字符通过UTF-8字符集进行编码后得到的二进制文件,然后将二进制转化为16进制,在每一个字符前面加上%作为分隔
   			UTF-8										   百分号编码
		"销售部"  ------> E9 94 80 E5 94 AE E9 83 A8 ------> %E9%94%80%E5%94%AE%E9%83%A8
Servlet线程安全问题
Servlet是单实例多线程环境下运行的
    Servlet对象只有一个,被多个线程共享;new出来的对象在堆空间,所有线程共享一个堆;
    
Servlet怎么解决线程安全问题:
    1. 不使用实例变量,尽量使用局部变量
    2. Servlet是单例的,所以剩下的方式只能考虑使用`synchronized`,线程同步机制    
转发和重定向
转发:request.getRequestDispatcher("/b").forward(request,response);
重定向:response.sendRedirect(request.getContextPath()+"/b");

转发和重定向的区别:
    - 相同点:都可以完成资源的跳转
    
    - 不同点:
          - 转发是request对象触发的,服务器内部进行转发
          - 重定向是response对象触发的,要将重定向的路径相应给浏览器
          - 转发是一次请求,浏览器地址栏上地址不变
          - 重定向是两次请求,浏览器地址栏上的地址发生变化
          - 重定向路径需要加项目名(webapp跟路径web目录)
          - 转发是在本项目内部完成资源的跳转
          - 重定向可以完成跨app跳转,例如可以跳转到`https://www.baidu.com`

什么时候采用转发,什么时候采用重定向?
    大部分情况下都使用重定向
    - 若想完成跨app跳转,必须采用重定向
    - 重定向可以解决浏览器的刷新问题
    - 若在上一个资源中向request范围中存储了数据,希望在下一个资源中从request范围中取出,必须使用转发
    
重定向原理是什么?
    response.sendRedirect("/jd/login");
    程序执行到以上代码,将请求路径`/jd/login`反馈给浏览器,
    浏览器又向web服务器发送了一次全新的请求:/jd/login
	浏览器地址栏上最终显示的地址是:/jd/login
重定向解决页面刷新问题
如果使用转发:
    浏览器只进行一次请求,如果此时浏览器进行刷新,浏览器刷新的是最后一次请求,即提交表单的请求,
    此时多次刷新浏览器,那么就会请求多次,就会执行多次Servlet,
    就会多次连接数据库插入数据,导致数据重复插入

如果使用重定向:
    服务器返回重定向的地址(success.html),浏览器就会请求新的地址,
    一共有两次请求:提交表单的请求和重定向的请求
    此时如果浏览器多次刷新,那么请求的也是重定向的success.html静态页面,
    不会因为刷新而导致多次提交表单
Cookie
Cookie是什么?
    - Cookie可以保存会话状态,但是这个会话状态是保留在客户端上的
    - 只要Cookie清除,或者Cookie失效,这个会话状态就没有了
    - Cookie是保存在浏览器客户端上的
    - Cookie可以保存在浏览器的缓存中,浏览器关闭Cookie消失
    - Cookie可以用保存在客户端硬盘文件中,浏览器关闭Cookie还在,除非Cookie消失	
    
创建Cookie:
	服务器创建Cookie并发送给浏览器
        //创建cookie
        Cookie cookie = new Cookie(String name, String value);
        //设置Cookie有效期
        cookie.setMaxAge(60*60*60);
        //设置Cookie绑定的路径
        cookie.setPath("/webapp19/user");
        //将cookie发送给浏览器
        response.addCookie(cookie);

Cookie绑定路径:
	在默认情况下,未设置Cookie绑定路径的Cookie,会绑定当前访问路径的"上级路径/",当浏览器访问这个路径,以及以这个路径作为根路径的地址时都会发送Cookie给服务器。
    `cookie.setPath();`来设置此Cookie绑定的访问路径
        
Cookie有效时长:
     `cookie.setMaxAge(int expiry)`
        - 参数是一个整数
        - 值为正数,以秒为单位指定Cookie的最长期限,Cookie存储在硬盘文件当中;
        - 值为负数,则此Cookie在关闭此窗口页面后即失效;
        - 如果为零,则删除此Cookie;
HttpSession
Session概述:
    1. Session表示会话,不止是在javaweb中存在,只要是web开发,都会有这种机制
    2. 在java中会话对应的类型是:javax.servlet.http.HttpSession 简称session/对话 
    3. Cookie可以将会话状态保存在客户端,而HttpSession可以将会话状态保存在服务器端
    4. HttpSession对象是一个会话级别的对象,一次会话对应一个HttpSession对象
    5. 在会话进程中,web服务器一直为当前这个用户维护着一个会话对象HttpSession
    6. 在web容器中,维护了大量的HttpSession对象,换句话说,在web容器中应该有一个“Session”列表

    思考:为什么当前会话中的每一次请求都可以获取到属于自己的Session会话对象?
    
什么是一次会话?
    - 一般可以这样理解:用户打开浏览器,在浏览器上发送多次请求,直到最终浏览器关闭,表示一次完整的回话。
    - 本质上理解:Session对象创建到最终超时销毁,才是真正意义的一次会话;因为即使浏览器关闭,可以通过重写URL的方式从其他电脑其他浏览器同样使用这个Session对象。   
    
获取Session对象:
    HttpSession session = request.getSession(无参数默认为true);
    注意:
        request.getSession(boolean)需要一个boolean类型的参数
        当参数为true(无参默认true)时,session存在则返回;如果session不存在,则创建一个新的session对象并返回
        当参数为false时,session存在则返回;如果session不存在,则返回null
    
Session实现原理:
    1. 浏览器发送请求,服务器对应的Servlet**首次调用**`request.getSession(true);`方法
       1.1 服务器会创建一个Session对象,该对象代表一次会话,同时生成一个对应的Cookie对象,并且Cookie对象的name是JSESSIONID,Cookie的value是32位长度的字符串
       1.2 服务器将Cookie的value和HttpSession对象绑定到session列表中(Map集合)
       1.3 服务器将Cookie发送到浏览器客户端,浏览器客户端将Cookie保存到缓存中(只要浏览器不关闭,Cookie不会消失)

    2. 浏览器再次发送请求,会自动提交缓存当中的Cookie
       2.1 当服务器Servlet**再次调用**`request.getSession();`方法时获取Session对象
       2.2 服务器接收到Cookie,验证Cookie的name为JSESSIONID,然后获取该Cookie的value
       2.3 通过Cookie的value去session列表(Map集合)中检索对应的HttpSession对象  
    
Session对象在什么时候销毁?
    1. web系统中引入了session超时的概念
    2. 当一段时间没有用户再访问session对象,此时session对象超时,web服务器自动回收session对象
    3. 设置Session对象失效时间(两次请求之间的最大时间间隔),优先级 A > B > C
        A:通过Java代码实现,单位秒
            HttpSession session = request.getSession();session.setMaxInactiveInterval(60*60);
        B:修改项目的web.xml文件,单位分钟
            <session-config>
                <session-timeout>60</session-timeout>
            </session-config>
        C:修改Tomcat默认配置,单位分钟,默认30分钟,CATALINA_HOME/conf/web.xml
            <session-config>
                <session-timeout>30</session-timeout>
            </session-config>
            
HttpSession中常用方法:
    void setAttribute(String name, Object value) 向会话范围中存储数据
    Object getAttribute(String name) 从会话范围中获取数据
    void removeAttribute(String name) 从会话范围中移除某个数据
    void invalidate() 销毁session对象
    void setMaxInactiveInterval(int interval) 设置session对象失效时间
        
ServletContext、HttpSession、HttpServletRequest对比:
    1. 以上都是范围对象:
         `ServletContext application` 是应用范围
         `HttpSession session` 是会话范围
         `HttpServletRequest request` 是请求范围
        
    2. 三个范围的大小 application > session > request 
        
    3. application完成跨会话(用户)共享数据;
       session完成跨请求共享数据,但是这些请求必须在同一个会话当中;
       request完成跨Servlet共享数据,但是这些servlet必须在同一个请求当中(请求转发)
        
    4. 使用原则:由小到大尝试,优先使用小范围
        
注意:
    1. HttpSession对象关联的这个Cookie的name是比较特殊的,在Java中就叫做:JSESSIONID
        
    2. 浏览器禁用Cookie会出现什么问题?怎么解决?
       - 浏览器禁用Cookie,则浏览器缓存中不再保存Cookie
       - 导致在同一个会话中,无法获取到对应的会话对象
       - 禁用Cookie之后,每一次获取的会话对象都是新的

       - 浏览器禁用Cookie之后,若还想拿到对应的Session对象,必须使用URL重写机制
        怎么重写URL:
         ```
     http://localhost:8080/webapp23/testSession;jsessionid=384A8D1CE7821C76EDC445F7D029C46A
         ```
         重写URL会给编程带来难度/复杂度,所以web站点是不建议禁用Cookie
         使用重写URL,即使换浏览器换电脑,只要在一定时间内访问的是同一个jsessionid,就可以得到同一个Session对象
             
    3. 浏览器关闭后,服务器端对应的session对象会被销毁吗?
       - 浏览器关闭后,服务器不会销毁session对象;因为B/S架构的系统基于HTTP协议,而HTTP协议是一种无连接/无状态的协议
       - 什么是无连接/无状态?
         请求的瞬间浏览器和服务器之间的通道是打开的,请求响应结束后,通道关闭;这样做的目的是降低服务器的压力
路径编写
超链接:<a href="/项目名/资源路径"</a>
    
form表单:<form action="/项目名/资源路径"</form>;; 
    
重定向:response.sendRedirect("/项目名/资源路径");

转发 :request.getRequestDispatcher("/资源路径").forward(request,response);

欢迎页面 :
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>WelcomeServlet</welcome-file>
	</welcome-file-list>
    
Servlet 路径:
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>cn.qkmango.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/资源路径</url-pattern>
    </servlet-mapping>
    
Cookie 设置path:cookie.setPath("/项目名/资源路径");
    
ServletContext:
    this.getServletConfig();
    ServletConfig config = getServletConfig();
    ServletContext context = config.getServletContext();
    //context.getRealPath("/WEB-INF/classes/db.properties")等于以下;
    context.getRealPath("/资源路径");
url-pattern的编写方式
一个Servlet可以编写多个url-pattern
精确匹配:
	<url-pattern>/system/hello</url-pattern>
	<url-pattern>/user</url-pattern>
扩展匹配:
	<url-pattern>/user/*</url-pattern>
后缀匹配:
	<url-pattern>*.action</url-pattern>
	<url-pattern>*.do</url-pattern>
全部匹配:
	<url-pattern>/*</url-pattern>
Servlet3.0注解
注解:Servlet3.0和JDK1.5及以后的版本才能使用
最简单的注解
	@WebServlet("/资源名")--->相当于url-pattern,"/资源名"指向了注解的这个Servlet;

多种数据的配置
	@WebServlet(url-Patterns = {"资源名1","资源名2","资源名3"},loadOnStartup = 0,
               initParams = {@WebParams(name = "",value = ""),@WebParams(name = "",value = "")}
               ....
               )
    
注意:同一个Servlet,要么使用web.xml文件配置,要么使用注解配置,但是不能使用两种方式同时配置。
XML
一种可扩展标记语言
XML文件的格式要求
    1)第一行必须是版本申明等信息
    2)有且仅有一个根标签
    3)不区分大小写,推荐使用小写
    4)自定义的标签不能是关键字
    5)标签之间必须正确嵌套
    6)标签名开头不能是数字
    7)标签可以有属性:属性名=”属性值”

XML的作用
    1)配置文件
    2)结构化存储数据
    3)数据交换(典型应用:AJAX)
 
dom4j解析XML文件  
    先导包
    再使用SAXReader将文件读成Document:
		Document document = reader.read("xxx.xml");
	获取根标签
        Element root = document.getRootElement();
	获取子标签
        List<Element> list = root.elements();
	循环获取子标签,再获取内容,
        获取内容用e.element("标签").getText();
		获取标签里面的属性用e.attributeValue("属性名")
            
XPath解析XML文件:
	XPath可以用来确定XML文档中某部分位置,它基于dom4j。
	使用之前先导包
	还是先使用SAXReader将文件读成Document:  
		Document document = reader.read("xxx.xml");
	再使用语法(查文档)
JSP
Java Server Page:Java服务器页面,动态网页。Java可以直接写在这个页面上。

JSP文件的执行流程:
	jsp文件被第一次访问的时候:jsp文件翻译成java文件,再编译成字节码文件,执行字节码文件。 
		通过查看编译后的字节码发现:JSP实际上就是一个Servlet
	jsp文件未被修改第N次访问:直接执行字节码文件

jsp与Servlet的区别:
    1、JSP主要功能是给用户看的页面,Servlet是控制器
    2、JSP被Tomcat翻译成java文件时直接赋予了九大内置对象,Servlet没有
    3、JSP是一个简化版的Servlet,功能有限。Servlet功能更加全面
    4、JSP不算一个纯粹的Java类,Servlet是一个纯粹的Java类

JSP页面组成:
    1、HTML标签及其内容

    2、Java代码
		第一种:脚本(脚本的内容被翻译到了_jsp方法的内部,因此脚本中不能定义java方法)
			语法:<% java代码 %>
		第二种:表达式(将数据输出到浏览器上)
			语法:<%=要输出的数据%>
		第三种:声明
			语法:<%! java代码 %>

    3、JSP指令
		三大指令:page,include,taglib;
		语法:<%@ 指令 指令内容%>

		第一种:page指令(页面描述)
			language:当前页面的脚本语言
			contentType:页面响应体的编码格式
			pageEncoding:页面的编码格式
			import:导包
			errorPage:错误跳转指定
				eg:   <%@ 
	page language="java" contentType="text/html;charset=utf-8" pageEncoding="utf-8" errorPage="xxx.jsp" 
    				%>
		第二种:include(包含)
			注意:使用include指令包含进来的JSP页面,是不会被翻译的(先把所有的合并在一起再编译)
			eg:<%@ include file="xxx.jsp"  %>

		第三种:taglib指令(引入其他工具)
			eg:<%@ taglib uri="xxx/jstl/core" prefix="c" %>
			<%@ taglib uri="xxx/jstl/functions" prefix="fn" %>

    4、注释:要注意的是jsp本身的注释<%--内容--%>不会被翻译到java代码中,而其他的注释会
EL表达式
Expression Language 是为了使JSP写起来更加简单

语法:${.....}

内部能进行的运算:算术、关系、逻辑、三元、空值判断${empty xxx}
JSP九大内置对象
pageContext------->页面内容对象
request----------->请求对象
session----------->会话对象
application------->服务器对象

response---------->响应对象
config------------>初始化数据对象
out--------------->输出对象
page-------------->当前页面对象,类似于Java中的this
exception--------->异常对象

Servlet中PrintWriter与JSP中out的区别:
    PrintWriter,不带缓冲区,直接写到页面上
    out,有缓冲区,先到缓冲区,再到页面上
JSP四大作用域
Servlet中的作用域:
        request:是请求范围
        session:是会话范围
        ServletContext:是应用范围

JSP中的作用域:
        pageContext:针对页面,在当前页面内有效。(是JSP独有的)
        request:请求范围
        session:会话范围
        application:应用范围

如果四大作用域中存入了相同key的数据?
	按照pageContext-->request-->session-->application的顺序寻找,找到了就结束

使用EL表达式,获取指定作用域的数据:
    pageContext-->pageScope
    request-->requestScope
    session-->sessionScope
    application-->applicationScope
JSP动作标签
一共13个
	需要了解的:jsp:forward,include,
	其他的:jsp:attribute,body,element,fallback,getProperty,output,
			param,params,plugin,setProperty,useBean

jsp:forward:跳转到某个页面
	<jsp:forward page="跳转页面"></jsp:forward>
jsp:include:将某个页面包含到本页面
	<jsp:include page="xxx.jsp"></jsp:include>
		注意:此标签在包含时,先将所有的JSP文件翻译成java文件,再组合到一起。

include指令(静态包含)与include标签(动态包含)的区别:
    1、语法不一样
    2、翻译方式不一样,指令只翻译一个文件,标签翻译所有文件
    3、指令的效率相对较高,标签较低
    4、指令不能携带数据,标签可以
JSTL标签库
Java server pages standarded tag library (jsp标准标签库)

步骤:导jar包->在jsp页面使用taglib指令来导入需要的标签库
	
核心:xxxx/jstl/core
	引入:<%@ taglib uri="xxx/jstl/core" prefix="c" %>
	使用:
        创建变量:<c:set var="name" value="xxx"></c:set>
        输出:<c:out value="${name}"></c:out>
        移除变量:<c:remove var="name"></c:remove>
        如果:<c:if test="${3>2}">输出内容</c:if>
        选择:
            <c:choose>
                <c:when test="xxx">输出的内容</c:when><c:otherwise>
                <c:when test="xxx">输出的内容</c:when><c:otherwise>
                </c:otherwise>
            </c:choose>
        循环(注意items双引号里面不要加空格):
             <c:foreach var="u" items="${list}">
                账号:${u.uname},密码:${u.pad}
             </c:foreach>
        
格式化:xxxx/jstl/fmt
                
函数:xxxx/jstl/functions
	引入:<%@ taglib uri="xxx/jstl/functions" prefix="fn" %>
	使用:
		字符串长度:${fn: length(str)}                
		.......
Ajax
Asynohronous JavaScirpt And Xml ------ 异步的JavaScript和XML
    它不是一种技术,是多种技术联合实现的产物。
    
Ajax是浏览器客户端上的前端技术
    
异步和同步有什么区别?
    A线程和B线程,并发执行,谁也不等谁,这就是异步
    A线程和B线程,在其中一个线程执行的时候另外一个线程需要等待,这就是同步;
    
传统的请求和Ajax请求有什么区别?
    传统的请求都是同步的,Ajax可以做到异步请求。
    
Ajax经典案例:Goole的auto_complete 、 Goole的map
    
浏览器本身是支持多线程并发的,其中ajax请求就是一个线程。一个页面上可以同时发送多个ajax请求,多个ajax对应浏览器对个线程。 
    
Ajax实现四步:
    1、创建Ajax核心对象XMLHttpRequest//浏览器内置的,可以直接使用。
    
    	var xhr;
    	if(window.XMLHttpRequest()){
            xhr = new XMLHttpRequest();
        } else{
            xhr = new ActiveXObject("Microsoft.XMLHTTP");//ie5和ie6只支持这种对象
        }

    2、注册回调函数
        /*
        	当xhr对象的readyState属性发生改变的时候,回调函数就会执行
        	XMLHttpRequest对象在请求和响应的过程中,该对象的属性readyState状态从0-4:
        	0:请求未初始化	1:服务器连接已建立		2:讲求已接收
        	3:请求处理中		 4:请求已完成,且响应已就绪
        */
    	xhr.onreadystatechange = function(){
        	if(xhr.readyState == 4){
                if(xhr.status == 200){//xhr.status属性可以获取到HTTP啥响应状态码。
                   //在浏览器端使用xhr对象接收服务器端响应回来的文本
                    var s = xhr.responseText;//responseText是属性
                    .....
                }else{
                    alert(xhr.status)
                }
            }
    	}
    3、开启浏览器和服务器之间的通道
        //这里只是开启通道
    	xhr.open(method,url,asyn);//asyn-true表示支持异步,asyn-false表示支持同步
		
		//如果是用的get请求,则在url后面添加要提交的数据 
		//如果是用post,则必须使用表单提交数据,以下代码行必须加上(可以从表单的enctype属性里面找)
		//Ajax post请求的乱码,需要在这里处理,注意字符集需要和浏览器及服务器字符集相同
		//xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded;charset=utf-8");

    4、发送Ajax请求
        xhr.send();//post请求提交数据在send里面提交eg:send(username=aaa&pwd=bbb)

注意:如果Ajax发送请求的方式是get,那么为了防止第n+1次访问走缓存,可以使用“加时间缀”的方式避免。
    var timeStamp = new Date().getTime();在路径后面加的时候可以使用下划线加:?_=timeStamp&.....
    
jQuery版AJAX
jQuery封装的AJAX常用的三种方法:
一、$.ajax({
        url:"",
        type:"get/post",
        data:{"key":"value","key":"value",...},
        dataType:"响应的数据类型",
        success:function(){},
        error:function(){}
    });	//参数顺序可变

二、$.get("url",{"key":"value","key":"value",...},function(){
    .......
	},dataType);//注意参数顺序不可变,函数是成功的回调函数

三、$.post("url","key":"value","key":"value",...,function(){
    ...........
	},dataType);    
返回数据的格式:
    text,json,html,script,jsonp,xml


表单序列化:
    作用:可以获取表单中用户输入的请求。
    关键字:serialize
    eg:var data = $("#form").serialize();
工具类
DBUtil:
public  class DBUTils{
	private DBUTils() {}
	
	static ComboPooledDataSource ds = new ComboPooledDataSource();
	static QueryRunner qr = new QueryRunner(ds);
	
	public static QueryRunner getQueryRunner() {
		return qr;
	}
}

DateUtils:
public class DateUtils {
	private DateUtils() {}
	public static Date stringToDate(String time) {
		Date date = null;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		try {
			date = sdf.parse(time);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return date;
	}
	public static String dateToString(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
		return sdf.format(date);
	}
}

PageUtil:
public class PageUtil {
	
	private int currPage;//当前页
	private int rows; //每页显示多少
	private int index;//偏移量
	private int countRows;//总记录数
	private int countPages;//总页数
	private int prevPage;//前一页
	private int nextPage;//后一页
	
	public PageUtil(String currPage,int rows,int countRows) {//只提供一个构造方法,用来生成对应的页码
		this.rows = rows;
		this.countRows = countRows;
		currPage(currPage);
		index();
		countPages();
		prevPage();
		nextPage();
	}
    //根据提供的参数初始化所有数据
	private void currPage(String currPage) {
        if (currPage == null || "".equals(currPage)) {this.currPage = 1;}else {this.currPage = Integer.parseInt(currPage);}}
	private void index() {index = (currPage-1)*rows;}
	private void countPages() {countPages = (countRows+rows-1)/rows;}
	private void prevPage() {if (currPage != 1) {prevPage = currPage-1;}else {prevPage = 1;}}
	private void nextPage() {if (currPage != countPages) {nextPage = currPage +1;}else {nextPage = countPages;}}
	生成所有属性的get方法,因为只需要别人调用,不需要别人设置!	
}
BaseServlet
public class BaseServlet extends HttpServlet {
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//设置字符编码集
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		String flag = request.getParameter("flag");//获取类型
		Class theClass = this.getClass();//获取字节码对象
		// 根据flag通过反射机制获取方法
		try {
			Method md = theClass.getDeclaredMethod(flag, HttpServletRequest.class,HttpServletResponse.class);
			md.setAccessible(true);// 打破修饰符
			md.invoke(this, request,response);// 调用方法
		} catch (Exception e) {e.printStackTrace();}}}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值