servlet

部署 :点项目右击,工具--》maven--->tager runtime  >Tomcat打钩
  ***********************
  *------day01-------*
  ************************
# 1. 什么是Servlet?
sun(oracle)公司制订的一种用来扩展web服务器功能的组件规范。

## (1)用来扩展web服务器功能
web服务器(比如apache web server,iis,nginx等)只能够处理静态资源的请求,
(即需要事先将html文档准备好,并存放到web服务器上),不能够处理动态资源
的请求(即需要通过一些计算,生成相应的html文档)。所以,需要扩展。
可以使用Servlet来扩展。

## (2)组件和容器
### 1)什么是组件?
符合规范,具有部分功能,并且需要部署到相应的容器里面才能运行的软件模块。
Servlet就是一个组件。

### 2)什么是容器?
符合规范,为组件提供运行环境的程序。
Servlet需要部署到Servlet容器里面才能运行,Servlet容器为
Servlet提供相应的运行环境(即网络相关的服务)。
    注:
        Tomcat是一个符合Servlet规范的容
# 2.如何写一个Servlet?
step1.写一个java类,实现Servlet接口或者继承HttpServlet。
step2.编译。
step3.打包。
    注:按照Servlet规范,创建一个具有如下结构的文件夹
    appname (文件夹的名称可以自定义,一般称之为应用名)
        WEB-INF
            classes (放.class文件)
            lib (放.jar文件 该文件夹可选)
            web.xml (部署描述文件)

step4.部署。
    将step3创建好的文件夹拷贝到容器相应的位置。
    注:
    也可以将step3创建好的文件夹使用jar命令压缩成".war"为后缀的文件,然后再拷贝。
step5.运行。
    启动容器,访问Servlet。
    打开浏览器,在地址栏输入 http://ip:port/appname/url-pattern。
    注:
        url-pattern是一个字符串,在web.xml中设置。
# 3.使用eclipse开发Servlet
## step1.集成tomcat
注:
        即使得eclipse可以管理tomcat(包括启动、关闭tomcat,自动部署等)
    可以参考
    http://doc.tedu.cn/tomcat/index.html
## step2.创建maven工程
# step3.添加一个java类
    注:
        继承HttpServlet
        override service方法。
参考代码:
    public class HelloServlet extends HttpServlet{    
    public HelloServlet() {
        System.out.println("HelloServlet的构造器");
    }
    @Override
    /**
     * Servlet容器(比如Tomcat)在收到请求之后,
     * 会解析请求数据包,将解析到的数据存放到request
     * 对象里面,同时,还会创建一个response对象。
     * 接下来,容器会创建Servlet对象,然后调用该
     * 对象的service方法来处理请求。
     * 注:
     *      作为开发人员,不用再处理网络相关的问题。
     * 比如,要读取请求参数,只需要调用request对象
     * 提供的方法即可;如果要向浏览器发送响应,只需要
     * 调用response对象提供的方法。
     */
    protected void service(
            HttpServletRequest request,
            HttpServletResponse response)
                    throws ServletException,
                    IOException {
        System.out.println(
                "HelloServlet的service方法");
        
        /*
         * 设置content-type消息头的值,告诉浏览器,
         * 服务器返回的数据类型。
         * 注:
         *     浏览器会按照指定的数据类型来解析。
         */
        response.setContentType("text/html");
        /*
         * 通过response对象获得一个输出流。
         */
        PrintWriter out = response.getWriter();
        /*
         * 将数据写到response对象上。
         * 注:
         *     容器会从response对象上提取数据,生成
         * 响应数据包并发送给浏览器。
         */
        out.println("Hello Kitty");
        out.close();
        }
    }


## step4.在web.xml文件中,添加Servlet配置信息。
参考配置:
        <servlet>
          <servlet-name>helloServlet</servlet-name>
          <!--
              类名一定要写完整(注意大小写)
              注:
                  容器会使用java反射完成类的加载,
                  如果类名写错,则容器会找不到该类的字节码文件。
           -->
          <servlet-class>web.HelloServlet</servlet-class>
          </servlet>
          <servlet-mapping>
          <servlet-name>helloServlet</servlet-name>
          <!--
              url-pattern用来定义访问路径,即
              如何调用该servlet
              (http://ip:port/appname/url-pattern)。
              
              比如:
                  http://localhost:8080/day01-lab/hello
           -->
          <url-pattern>/hello</url-pattern>
          </servlet-mapping>


# 4.Servlet是如何运行的?
比如,在浏览器地址栏输入http://ip:port/appname/hello
step1.浏览器依据ip、port建立与Servlet容器之间的连接。
step2.浏览器创建请求数据包并发送给容器。
step3.容器解析请求数据包中的数据,然后将解析到的数据添加到
request对象里面,同时,容器还会创建一个response对象。
step4.容器依据请求路径,创建对应的Servlet对象,然后调用该对象的
service方法。
    注:
        容器会将request对象和response对象作为参数传递过来。
    开发人员可以通过调用request对象提供的方法来获得请求数据包中
    的数据(比如请求参数),然后将处理结果写到response对象即可。
sep5.容器通过response对象获得处理结果,然后创建响应数据包并发送给浏览器。
step6.浏览器解析响应数据包中的数据,生成相应的页面。
# 5.常见问题
## (1)404
含义:404是一个状态码,表示服务器依据请求路径找不到对应的资源。
原因:
    a.请求路径写错。没有严格按照http://ip:port/appname/url-pattern
    来写。
    b.没有部署或者部署失败。
## (2)500
含义:500也是一个状态码,表示服务器端程序运行出错。

原因:
    a.没有严格按照Servlet规范来写代码和配置。
    比如,没有继承HttpServlet。
    又比如,<server-class>类名写错。
    b.代码不严谨。
    比如,对请求参数值没有做检查就做类型转换。
## (3)405
含义:405也是一个状态码,表示服务器找不到处理方法。
原因:
    service方法没有正确override。
  *------day02-------*
# 1.http协议(了解)
## (1)什么是http协议?
是一种网络应用层协议,规定了浏览器如何与web服务器之间进行通信以及相应的
数据包的结构。    
应用层协议TCP/传输层协议------->(只负责给数据打包)-------->IP/网路层协议------>(发送数据包)
Tcp/IP 称为传输层和网络层协议。
    浏览器与web服务器之间如何通信?
    step1.建立连接      browser---建立连接----->web server
    step2.发送请求      browser---打包发送请求---->web server
    step3.发送响应      browser<---打包发送响应---- web server
    step4.关闭连接      browser<---断开连接---- web server
    如果浏览器要再发送请求,需要重新建立新的连接,即“一次请求,一次连接”。
    优点:web服务器可以利用有限的连接为尽可能多的请求服务。
## (2)数据包的结构
1)请求数据包            
    a.请求行 (请求方式(get/post) 请求资源路径(url) 协议和版本(Http/1.0))
    b.若干消息头
        消息头是一些键值对(使用": "隔开),浏览器与web服务器之间
        可以通过发送一些消息头来传递一些特定的信息。比如,浏览器
        可以发送"user-agent"消息头来告诉web服务器浏览器的类型和版本。
    c.实体内容
        只有当请求方式为post时,实体内容才会有数据。
2)响应数据包
    a.状态行 (协议和版本(Http/1.0) 状态码 状态描述)
        注:
            状态码是一个三位数字,描述服务器处理请求的一种状态
          200: 正解
             500: 系统出错
             404: 依据请求路径找不到对应的资源
             405: 找不到处理方法
    b.若干消息头
        web服务器也可以发送一些消息头给浏览器,比如,可以发送"content-type"消息头,告诉浏览器,服务器返回的数据类型和编码。
    c.实体内容
        程序的处理结果,浏览器会解析出来,生成相应的页面。
## (3)两种请求方式  
1)get请求
    a.哪一些情况下浏览器会发送get请求?
        在浏览器地址栏输入某个地址
        点击链接
        表单默认的提交方式
    b.特点
        b1.不安全,会将请求参数显示在浏览器地址栏。
        注:
            有一些网络设备,比如路由器,会记录请求地址。
        b2.只
        能提交少量的数据(2K左右),会将请求参数添加到请求资源路径的后面(即请求行里面)。
        注:
            整个请求行,大约能存放2k左右的数据。
2)post请求
    a.哪一些情况下,浏览器会发送post请求?
        将表单的method属性设置为post。
    b.特点
        b1.不会将请求参数显示在浏览器地址栏,相对安全一些。
        注:
            http协议对数据包并不会加密处理,所以,对于敏感数据
        需要加密(使用https协议)。
        b2.会将请求参数添加到实体内容里面,可以提交大量数据。
# 2.Servlet输出中文
## (1)为什么会有乱码?
out.println方法在默认情况下,会使用"iso-8859-1"来编码。
## (2)如何解决?
    response.setContentType(
                "text/html;charset=utf-8");
# 3.如何读取请求参数值?
## (1)方式一
String request.getParameter(String paramName);
    请求值写错。返回NULL
    注:
        paramName是请求参数名,如果请求参数名写错,返回null。
## (2)方式二
String[] request.getParameterValues(String paramName);
    不填,返回null
    注:
        当有多个请求参数名相同的时候,使用此方法。
        对于多选框,如果一个都不选择,会返回null值。
##输出中文
1.得到输出流:out.println
2.设置满足标准:response.setContentType("text/html;charset=utf-8");
# 4.表单包含有中文参数值,如何处理?
## (1)为什么会有乱码?
    提交表单时,浏览器会对中文参数值进行编码(比如,使用utf-8),
    而服务器端默认会使用iso-8859-1来解码,所以,会产生乱码。
    注:
        浏览器会使用打开该表单所在的页面时的字符集来编码。
## (2)如何解决?
### 如果是get请求
String request.getParameter(String paramName);
注:
    paramName是请求参数名,如果请求参数名写错,返回null
![](s1.png)    
### 如果是post请求
    String  request.setCharacterEncoding("utf-8");
        *****
            加在所有request最前面
 ***********************
  *------day03-------*
  ************************    
# 1.访问数据库
## (1)步骤
step1.导包(jdbc驱动、连接池)。
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
    </dependencies>
step2.拷贝DBUtils到util包下。
step3.拷贝jdbc.properties文件。
step4.测试DBUtils。
step5.建表
    create table t_user(
        id int primary key auto_increment,
        username varchar(50) unique,
        password varchar(30),
        email varchar(30)
    );
step6.在service方法里面,使用jdbc api访问数据库。
***********************properties
使用properties获得属性配置文件的属性值.
step1.先配置XXXX.properties结尾的properties文件。
        例:
        driver=com.mysql.jdbc.Driver
        url=jdbc:mysql://localhost:3306/db3
        username=root
        password=
        InitialSize=3
        MaxActive=4:
注:内容都是一键值对的形式。
step2.
1.)得到文件流
Properties prop=new Properties();
2.)把文件加载到属性对象中
InputStream ips=DBUtils.class.getClassLoader()
.getResourceAsStream("jdbc.properties");
3.)获取属性配置文件中的数据
        prop.load(ips);            
        String driver=prop.getProperty("driver");
        String url=prop.getProperty("url");
        String username=prop.getProperty("username");
        String password=prop.getProperty("password");
        int size= Integer.parseInt(prop.getProperty("InitialSize"));
                    int max=Integer.parseInt(prop.getProperty("MaxActive"));                
//将用户信息插入到数据库
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = DBUtils.getConn();
            String sql = "INSERT INTO t_user "
                    + "VALUES(null,?,?,?)";
            ps = conn.prepareStatement(sql);
            ps.setString(1, username);
            ps.setString(2, pwd);
            ps.setString(3, email);
            ps.executeUpdate()    
            out.println("添加成功")    
        } catch (SQLException e) {
            /*
             * step1.记日志(保留现场)
             */
            e.printStackTrace();
            /*
             * step2.看异常能否恢复,如果不能够
             * 恢复(比如,数据库服务停止了、网络
             * 中断了等等,这样的异常我们通常称之为
             * 系统异常),则提示用户稍后重试。
             * 如果能够恢复,则立即恢复。
             */
            out.println("系统繁忙,稍后重试");
        }finally {
            DBUtils.close(conn, ps, null);
        }

# 2.重定向
## (1)什么是重定向?
服务器通知浏览器向某个地址发送请求。
    注:
        服务器可以通过发送302状态码和Location消息头(该消息头的值
        是一个地址,一般称之为重定向地址),浏览器收到之后,会立即
        向重定向地址发送请求。
## (2)如何重定向?
response.sendRedirect(String url);
send发送,redirect重定向
    注:
        a.url就是重定向地址。
        b.重定向之前,容器会先清空response对象上存放的所有数据。
## (3)特点
a.重定向地址是任意的。
b.重定向之后,浏览器地址栏的地址会发生变化。
# 3.DAO(扩展)
## (1)DAO是什么? (Data Access Object)
封装了数据访问逻辑的对象。
## (2)如何写一个DAO?
step1.写一个java类,用于存放从数据库中查询出来的数据。
    注:
        关系数据库里面存放的是一条条记录,而java语言擅长处理
        对象,所以,我们经常有这样的需要,即将记录转换成一个对应的
        java对象,方便处理。
step2.写一个java类,提供一些访问数据库的方法。
##(3)DAO的优点    
    DAO作为一种设计模式的优点
a.方便测试
        注:
            如果将jdbc代码写在servlet类里面,需要部署整个web应用才能测试,而将jdbc代码写在DAO类里面,可以直接测试(不需要部署整个servlet)。
b.方便分工协作
c.方便代码的维护
        注:
        dao实现发生改变不影响调用者。
  *------day04-------*    
# 1.DAO(扩展)
## (1)DAO是什么? (Data Access Object)
封装了数据访问逻辑的对象。
## (2)如何写一个DAO?
step1.写一个java类(实体类),用于存放从数据库中查询出来的数据。
    注:
        关系数据库里面存放的是一条条记录,而java语言擅长处理
    对象,所以,我们经常有这样的需要,即将记录转换成一个对应的
    java对象,方便处理。
step2.写一个java类,提供一些访问数据库的方法。
## (3)DAO的优点?
a.方便测试
    注:
        如果将jdbc代码直接写在servlet类里面,需要部署整个web应用才能
    测试,而将jdbc代码写在DAO类里面,可以直接测试(不需要部署整个应用)。
b.方便分工协作
c.方便代码的维护

    注:
        dao实现发生改变,比如原来使用jdbc,现在使用mybatis,
    并不影响调用者(即不影响Servlet)。
# 2.jsp
## (1)jsp是什么?
sun公司制订的一种服务器端的动态页面技术规范。
    注:
        因为使用servlet虽然也可以生成动态页面,但是过于繁琐(
    需要使用大量的out.println语句),并且不利于页面的维护(如果
    要修改页面,就需要修改java代码),所以,sun才制订了jsp技术规范。
        jsp是一个以.jsp为后缀的文件,该文件主要由html和少量的
    java代码组成。容器会将这个文件自动转换成一个servlet然后执行。
        jsp本质就是一个servlet!
## (2)如何写一个jsp?
### step1. 写一个以.jsp为后缀的文件。
### step2. 在文件里面,可以使用如下元素:
1)html(css,javascript)
    直接写即可。
2)java代码
    a.java代码片断:
    <% java代码   %>
    b.jsp表达式
    <%= java表达式 %>
3)隐含对象
    a.什么是隐含对象?
    可以直接使用的对象,比如out,request,response。
    b.为什么可以直接使用这些隐含对象?
    因为容器在生成对应的servlet源代码时,会自动添加获得这些
    对象的代码。
4)指令
    
    a.什么是指令?
    告诉容器,在将jsp转换成一个Servlet时,额外做一些处理,比如,
    导一些包。
    b.指令的语法
    <%@ 指令名 属性=值 %>
    c.page指令
        import属性:用于指定要导入的包名。比如
            <%@ page import="java.util.*"%>
            <%@ page import="java.util.*,java.text.*"%>
        contentType属性:用于设置response.setContentType方法的内容。
        pageEncoding属性:见下图        
## (3)jsp是如何执行的?
step1.容器将jsp转换成一个Servlet。
    html(css,javascript) -----> service方法里面,使用out.write输出。
        注(了解):
            out.println方法会将null直接输出,而out.write方法会将
            null转换成""输出(更友好)。
    <%     %>      ------->  service方法里,照搬。
    <%=    %>      ------->  service方法里,使用out.print方法输出。
step2.容器再调用该Servlet。
    注:
        容器会将该Servlet编译,然后实例化,调用其service方法。
*------day05-------*        
# 1. include指令
## (1)语法
    <%@ include file=""%>
    注:
        file属性用来指定被包含的文件名。当容器在将jsp转换成
    对应的servlet源代码时,会将file属性指定的文件的内容插入到
    该指令所在的位置。

## (2)细节
    被包含的jsp文件并没有对应的Servlet。
# 2.转发
## (1)什么是转发?
一个web组件将未完成的处理交给另外一个web组件继续做。
    注:
        web组件是servlet和jsp的统称。
        通常是一个Servlet获得数据之后转交给jsp来展现。
## (2)如何转发?
step1.将数据绑订到request对象上。
    request.setAttribute(String name,Object obj);
    汉译:attribute『/əˈtrɪbju』:认为某事物由某人[某事物]引起或产生
    注:
        name:绑订名
        obj:绑订值
        依据绑订名获得绑订值,如果绑订值不存在,返回null。
        Object request.getAttribute(String name);
step2.获得转发器。
    RequestDispatcher rd =
        request.getRequestDispatcher(String uri);
dispatcher(汉义):调度器
    注:
        RequestDispatcher是一个接口,该方法会返回一个符合该接口
        要求的对象,该对象我们称之为转发器
        转发的本质是一个web组件通知容器去调用另外一个web组件。
        可以将转发器看作是一个媒介,通过该媒介,就可以通知容器去
        调用另外一个web组件了。
        uri就是转发的目的地,通常是一个jsp。

step3.转发
    
    rd.forward(request,response);
forward(汉译):转发。    
![](forward.png)
## (3)特点
a.转发之后,浏览器地址栏的地址是不变的。
b.转发的目的地有限制,要求属于同一个web应用。
#3.比较转发与重定向
## (1)能否共享request?
    转发可以、重定向不行。
    注:
        a.容器收到请求之后,会立即创建request和response对象,一旦
    响应发送完毕,会立即销毁这两个对象。也就是说,request和response
    对象的生存时间是一次请求和响应期间存在。
        b.转发是一次请求,重定向是二次请求。
转发是一件事情没有做完交给另一个servlwt来做,重定向是一件事情做完了,转到下一个事情。(就像流水线操作,我负责的部分干完了 流下去)
## (2)浏览器地址栏的地址有无变化?
    转发没有变化,重定向有变化。
## (3)目的地有无限制?
    转发有(要求属于同一个应用),重定向无任何限制。

    *------day06------*
# 1.状态管理
## (1)什么是状态管理?
    将浏览器与web服务器之间多次交互当做一个整体来处理,并且将多次
    交互所涉及的数据(即状态)保存下来。
## (2)如何进行状态管理?
    a.将状态保存在浏览器端(Cookie)
    b.将状态保存在服务器端(Session 会话)
## (3)Cookie
### 1)Cookie是什么?
服务器临时存放在浏览器端的少量数据,用于跟踪用户状态。

### 2)Cookie的工作原理
当浏览器访问服务器时,服务器时可以将少量数据以set-cookie消息头的形式
发送给浏览器,浏览器会保存下来    ;
当浏览器再次访问服务器时,会将之前保存的这些数据以cookie消息头的形式
发送给服务器。
### 3)如何添加Cookie
    Cookie c = new Cookie(String name,String value);
    response.addCookie(c);
    注:
        name一般称之为cookie的名称,value称之为cookie的值。

### 4)如何读取Cookie?
    
    Cookie[] request.getCookies();
    注:
        该方法有可能返回null。

    String cookie.getName();
    String cookie.getValue();

### 5)生存时间问题
a.默认情况下,浏览器会将cookie保存在内存里面。浏览器如果关闭,则
cookie会被删除。
b.可以调用setMaxAge方法来设置cookie的生存时间。

    cookie.setMaxAge(int seconds);
    注:
        单位是秒。 365 * 24 * 60 * 60
        seconds > 0: 浏览器会将cookie保存在硬盘上(一般是文件的形式),
                    超过指定的时间,cookie会被删除。
        seconds < 0: 默认情况(即保存在内存里面)。
        seconds = 0: 删除cookie。
            比如,要删除一个名称为username的cookie:
            Cookie c = new Cookie("username","");
            c.setMaxAge(0);
            response.addCookie(c);

### 6)编码问题
a.cookie只能保存合法的ascii字符,如果是中文,需要转换成对应的
ascii字符的形式。
    
b.可以使用以下方法进行处理

    String URLEncoder.encode(String str,String charset);
    String URLDecoder.decode(String str,String charset);

c.建议,在添加cookie时,不管是否为中文,统一进行编码处理。

### 7)路径问题
a.什么是cookie的路径问题?

    浏览器访问服务器上的某个地址时,会比较该地址是否符合cookie的路径
    要求,只有符合条件cookie才会被发送。

b.Cookie的默认路径

    默认路径等于添加该cookie的web组件的路径。
    比如,/day06/biz01/addCookie.jsp添加了一个cookie,则该
    cookie默认的路径是"/day06/biz01"。

c.哪一些cookie会被发送?

    请求地址等于cookie的路径或者是其子路径,则该cookie会被发送。

    比如,cookie的路径是"/day06/biz01",则
    "/day06/findCookie1.jsp", 不会被发送;
    "/day06/biz01/findCookie2.jsp",会被发送;
    "/day06/biz01/sub/findCookie3.jsp",会被发送。

![](s2.png)

d.可以调用setPath方法来修改cookie的路径

    cookie.setPath(String path);




***********************
*------day07------*
************************


### 8)Cookie的限制
a.Cookie可以被用户禁止。

b.不安全。

    注:
        Cookie是将状态保存在浏览器端,服务器端并不保存任何状态,
    所以,对于敏感数据,尽量不要保存在cookie里面,如果一定要保存,
    则加密。

c.保存的数据大小有限制。

    注:
        一般是4k左右。

d.数量也有限制。

    注:
        一般是几百个左右。

e.只能存放字符串。


# 1. Session (会话)
## (1)什么是Session?
服务器为了保存用户状态而创建一个特殊的对象。

## (2)工作原理
浏览器访问服务器时,服务器创建一个特殊的对象(即session对象,该对象
有一个唯一的id,一般称之为sessionId),服务器将sessionId以cookie的方式
发送给浏览器。
当浏览器再次访问服务器,会将sessionId发送过来,服务器依据sessionId
就可以找到对应的session对象。

## (3)如何获得session对象?
### 1)方式一
HttpSession s = request.getSession(boolean flag);

    注:
        HttpSession是一个接口,request.getSession方法会返回一个
        实现了该接口的对象,该对象我们称之为session对象。
        当flag为true时:
            先查看请求当中是否有sessionId,如果没有,则创建一个
            session对象;如果有sessionId,则依据该sessionId查找
            对应的session对象,如果找到了,则返回该对象,找不到,
            则创建一个新的session对象。
![](session.png)

        当flag为false时:
            先查看请求当中是否有sessionId,如果没有,返回null;
            如果有sessionId,则依据该sessionId查找
            对应的session对象,如果找到了,则返回该对象,找不到,
            返回null。
    
### 2)方式二
HttpSession s = request.getSession();

    注:
        等价于request.getSession(true);

## (4)session对象的常用方法
a.获得sessionId
String session.getId();

b.绑订数据
session.setAttribute(String name,Object obj);

c.依据绑订名获得绑订值
Object session.getAttribute(String name);

    注:如果绑订名对应的值不存在,返回null。

d.解除绑订
session.removeAttribute(String name);

![](count.png)


## (5)session超时
### 1)什么是session超时?
服务器会将空闲时间过长的session对象删除掉。

    注:
        为了节省内存空间。
        服务器默认的超时时长一般是30分钟。

### 2)如何修改session超时时间?
方式一 修改服务器的配置文件

     <session-config>
        <session-timeout>30</session-timeout>
     </session-config>

方式二 编程的方式

    session.setMaxInactiveInterval(int seconds);

    注:
        设置两次请求之间的最大间隔时间。如果超过这个间隔时间,
        session对象会被删除。

## (6)删除session
session.invalidate();

练习:写一个Servlet,输出用户上次访问的时间,如果是第一次访问,则
输出“你是第1次访问”。


## (7)session验证 (案例)
step1.登录成功之后,在session对象上绑订一些数据,比如:

    session.setAttribute("user",username);

step2.当用户发送请求过来,检查session对象上是否有对应的数据,比如:
    
    注:
        只有访问受保护的资源时,才需要进行session验证。

    Object obj = session.getAttribute("user");
    if(obj == null){
        //没有登录,重定向到登录页面
        response.sendRedirect("login.jsp");
    }

![](login.png)


***********************
*------day08------*
************************
## (8) 比较session与cookie
session作为一种服务器端的状态管理技术、相对于cookie更安全、
可以存放更多的数据、支持更丰富的数据类型,缺点是会占用服务器端的
大量的内存资源。


# 1.Servlet的生命周期
## (1)什么是Servlet的生命周期?
Servlet容器如何创建Servlet实例、如何对其进行初始化操作、
如何调用其方法来处理请求、以及如何销毁其实例的整个过程。
也可以用一句话来描述:即容器是如何管理Servlet的。

![](life.png)

## (2)生命周期分成哪几个阶段?

### 1)实例化
a.什么是实例化?

    容器调用Servlet的构造器,创建Servlet实例。

b.什么时候实例化?

    默认情况下,容器只有在收到请求之后,才会创建Servlet实例。
    注:
        容器只会创建一个Servlet实例!
    
    在添加适当配置之后,可以让容器启动之后,立即创建Servlet实例,
    如下图。
![](s1.png)        

### 2)初始化
a.什么是初始化?

    容器在创建好Servlet实例之后,会调用该实例的init(ServletConfig config)方法。
    注:
        该方法只会执行1次!

b.GenericServlet已经提供了init(ServletConfig config)方法的实现。

    该方法是这样实现的:
        将容器传递过来的ServletConfig对象保存下来了,并且提供了一个
        getServletConfig方法来获得该对象。另外,该方法还调用了一个
        init()方法。作为开发人员,如果要扩展,只需要override init()方法
        即可,如下图。

![](init.png)

c.ServletConfig提供了一些实用方法,比如读取初始化参数的方法。

![](s3.png)    
![](s4.png)        



### 3)就绪(调用)
a.什么是就绪?

    容器在收到请求之后,会调用Servlet实例的service方法来处理请求。

b.HttpServlet已经提供了service方法的实现。
    
    该方法是这样实现的:
        依据请求类型调用对应的doXXX方法,比如get请求调用doGet方法,
        post请求调用doPost方法。doXXX方法只是简单地抛出了一个异常。

    作为开发人员,在开发一个Servlet时,有两个选择,一是直接override
    HttpServlet的service方法,或者override HttpServlet的doGet和
    doPost方法。

![](service.png)
    

### 4)销毁
a.什么是销毁?

    容器在删除Servlet实例之前,会调用该实例的destroy方法。
    注:
        该方法只会执行一次。

b.GenericServlet已经提供了destroy方法的实现。
    
    该方法的实现为空(什么都没有做),开发人员可以override
    destroy方法来扩展。


## (3)相关的接口与类(了解)
a. Servlet接口
    init(ServletConfig config);
    service(ServletRequest req,ServletResponse response);
    destroy();

b. GenricServlet抽象类
    实现了Servlet接口中的部分方法(init,destroy)。

c. HttpServlet抽象类
    继承了GenericServlet,实现了service方法。


    
# 练习 计算一个人的BMI指数。

    算法:

    BMI指数 = 体重(公斤) / 身高(米) / 身高(米)
    
    如果是男性:
        如果 bmi指数 < 20 体重过轻。
        如果 bmi指数 > 25   体重过重。
        否则 正常。
    如果是女性:
        如果 bmi指数 < 19 体重过轻。
        如果 bmi指数 > 24   体重过重。
        否则 正常。

![](exec.png)

***********************
*------day09------*
************************
# 1.容器是如何处理请求资源路径的?
比如,在浏览器地址栏输入http://ip:port/appname/abc.html,容器如何处理?

step1. 容器默认会认为访问的是一个Servlet,所以容器会查看web.xml中
有没有匹配的Servlet。
    
    有三种匹配方式:
    精确匹配:
        <url-pattern>的值必须等于请求路径。比如说,对于上述请求,
        url-pattern的值必须是"/abc.html"。
        
    通配符匹配:
        使用 "*" 匹配任意的零个或者多个字符。比如:
        <url-pattern>/*</url-pattern>
        <url-pattern>/demo/*</url-pattern>
 
    后缀匹配:
        使用"*."开头,后接一个后缀,用来匹配所有以该后缀结尾的请求。
        比如:
        <url-pattern>*.do</url-pattern>
        <url-pattern>*.action</url-pattern>

step2.如果没有匹配的Servlet,则容器会查找对应的文件。


# 2.如何让一个Servlet处理多种请求?
step1.使用后缀匹配,比如
    <url-pattern>*.do</url-pattern>

step2.分析请求资源路径,进行不同的处理

        //step1.获得请求资源路径
        String uri = request.getRequestURI();
        System.out.println("uri:" + uri);
        
        //step2.分析请求资源路径,进行不同的处理
        String path =
                uri.substring(
                        uri.lastIndexOf("/"),
                        uri.lastIndexOf("."));
        System.out.println("path:" + path);
        
        if("/list".equals(path)) {
            System.out.println("处理用户列表请求");
        }else if("/add".equals(path)) {
            System.out.println("处理添加用户请求");
        }


# 练习
将AddUserServlet,DelUserServlet合并到ActionServlet。

# 3.过滤器
## (1)什么是过滤器?
Servlet规范当中定义的一种特殊的组件,用于拦截Servlet容器的调用过程。

    注:
        容器收到请求之后,会先调用过滤器,再调用Servlet。

![](filter.png)

## (2)如何写一个过滤器?
step1.写一个java类,实现Filter接口。

step2.在接口方法当中,实现拦截处理逻辑。

step3.配置过滤器。(web.xml)

# 练习
写一个过滤器,检查评论的字数,如果超过10个字,则提示
“评论的字数过多”。

## (3)过滤器的优先级
当有多个过滤器都满足拦截的要求,则容器依据<filter-mapping>
配置的先后顺序来执行。

## (4)初始化参数
step1.配置初始化参数

    <!-- 配置初始化参数 -->
      <init-param>
          <param-name>illegal</param-name>
          <param-value>狗</param-value>
      </init-param>

step2.使用FilterConfig对象提供的方法来读取
    
    //读取初始化参数
        String illegal =
                config.getInitParameter("illegal");



***********************
*------day10------*
************************


# 过滤器的优点
a.在不修改原有代码的基础上,添加一些简单的功能。

b.将多个组件相同的功能集中写在一个类里面(即过滤器里面),方便
代码的维护。


# 1.监听器
## (1)什么是监听器?
Servlet规范当中定义的一种特殊的组件,用于监听Servlet容器产生的事件并
进行相应的处理。

    注:
        容器产生的事件分为两类:
        a.生命周期相关的事件:
            容器创建了或者销毁了request、session、servlet上下文
            时产生的事件。
        
        b.绑订数据相关的事件:
            调用了request、session、servlet上下文的setAttribute、
            removeAttribute时产生的事件。

## (2)servlet上下文
***重要
a.什么是servlet上下文?

    容器启动之后,会为每一个web应用创建唯一的一个符合ServletContext
    接口要求的对象,该对象我们称之为servlet上下文。

![](s1.png)

b.如何获得servlet上下文?
    
    GenericServlet,ServletConfig,FilterConfig,HttpSession
    都提供了一个方法(getServletContext)来获得上下文。

c.作用
    
c1.绑订数据
        setAttribute,getAttribute,removeAttribute
    注:
        request、session、servlet上下文都可以绑订数据,有什么区别?
        区别1:
            绑订的数据生存时间不一样,按照生存时间的长短来排序,依次是
        request < session < servlet上下文。
            在满足使用条件的情况下,优先使用生命周期短的。
        区别2:
            绑订到session对象上的数据,只有与之对应的用户能访问到,
            而绑订到上下文上的数据,所有用户都能访问到。

![](s4.png)

c2.读取全局的初始化参数
    
    <!-- 配置全局的初始化参数 -->
      <context-param>
          <param-name>company</param-name>
          <param-value>北京达内科技有限公司</param-value>
      </context-param>

    String company =
                sctx.getInitParameter("company");


## (3)如何写一个监听器?
step1.写一个java类,实现相应的监听器接口。
    
    注:
        要依据监听的事件类型去选择实现相应的接口,比如,
        要监听session对象的创建和销毁,需要实现
        HttpSessionListener接口。

step2.在监听器接口方法当中,实现相应的监听处理逻辑。

step3.配置监听器。(web.xml)

## 案例(统计在线人数)
![](count.png)


# 2.路径问题
## (1)什么是路径问题?
在链接、表单提交、重定向以及转发时,如何填写相应的路径。

    比如:
        <a href="del.do">
        <form action="login.do">
        response.sendRedirect("login.jsp")
        request.getRequestDispatcher("error.jsp")

## (2)相对路径
不以"/"开头的路径。

## (3)绝对路径
以"/"开头的路径。

## (4)如何写绝对路径
链接、表单提交、重定向从应用名开始写,转发从应用名之后开始写。

    注,不要将应用名直接写在路径里面,而应该使用以下
    方法来获得实际部署时的应用名。
    String  request.getContextPath();

***********************
*------day11------*
************************
# 1.Servlet的线程安全问题
## (1)为什么说Servlet会有线程安全问题?
a.容器只会创建一个Servlet实例。

b.容器收到一个请求,就会启动一个线程来处理。
这样,就有可能有多个线程同时去调用某个Servlet实例,就有可能
产生线程安全问题(比如,这些线程要修改该实例的某个属性)。

![](s1.png)

## (2)如何解决?
使用synchronized对有可能产生线程安全问题的代码加锁。

    注:加锁会影响性能。

**************************************************************
# 2.Servlet小结
## (1)Servlet基础

1)什么是Servlet?

2)如何写一个Servlet?

3)Servlet是如何运行的?

4)http协议(了解)
    
    a.什么是http协议?
    b.特点
    c.数据包的结构(消息头、状态码)
    d.两种请求方式
    

## (2)Servlet核心
1)如何读取请求参数值?

2)表单包含有中文参数值,如何处理?

3)Servlet输出中文,如何处理?

4)容器如何处理请求资源路径?

5)如何让一个Servlet处理多种请求?

6)转发与重定向

    a.什么是重定向?
    b.如何重定向?
    c.重定向的特点
    d.什么是转发?
    e.如何转发?
    f.转发的特点?
    g.转发与重定向的区别?

7)Servlet的生命周期
    
    a.什么是Servlet的生命周期?
    b.分成哪几个阶段?
    c.相关的接口与类

8)Servlet线程安全问题

    a.为什么说Servlet会有线程安全问题?
    b.如何解决?

9)Servlet上下文

    a.什么是Servlet上下文?
    b.如何获得Servlet上下文?
    c.作用
        request、session、Servlet上下文绑订数据的区别
        (生存时间、可访问的范围)。

10)路径问题
    
    a.什么是相对路径?
    b.什么是绝对路径?
    c.如何写绝对路径?


## (3)状态管理
1)什么是状态管理?

2)如何进行状态管理?

3)Cookie

    a.什么是Cookie?
    b.工作原理 (set-cookie,cookie)
    c.如何添加Cookie?
    d.添加Cookie的三个问题
        编码问题
        生存时间问题
        路径问题  
    e.如何读取Cookie?
    f.cookie有哪些限制?
    
4)Session
    
    a.什么是Session?
    b.Session的工作原理
    c.如何获得Session对象?
    d.常用方法
    e.Session超时
    f.如何删除session?          

## (4)数据库访问
    
    a.什么是dao?
    b.如何写一个dao?

## (5)过滤器和监听器

    a.什么是过滤器?
    b.如何写一个过滤器?
    c.优先级
    d.初始化参数
    e.优点(了解)
    f.什么是监听器?
    g.如何写一个监听器?
    
## (6)案例

    a.用户管理
    b.登录(session验证)



# 3. jsp基础
## (1)jsp是什么?
sun公司制订的一种服务器端动态页面技术规范。

    jsp是一个以.jsp为后缀的文件,主要内容是html加少量的java代码,
    容器会将jsp转换成一个对应的Servlet然后执行。


## (2)如何写一个jsp?
step1.添加一个以.jsp为后缀的文件。

step2.可以使用如下元素。

### 1)html(css,js)
直接写即可

### 2)java代码
a. java代码片断

    <%   java代码 %>

b. jsp表达式

    <%=  java表达式 %>

c. jsp声明  (a1.jsp)

    <%! 声明变量或者方法  %>

### 3)指令
a.什么是指令?

    通过指令,可以告诉容器,在将jsp转换成Servlet时,做一些额外的处理,
    比如导包。

b.指令语法

    <%@ 指令名  属性=值  %>
    注:
        多个属性要使用空格隔开。

c.page指令
    
    import属性: 导包。
    pageEncoding属性:指定jsp文件的编码。
    contentType属性: response.setContentType();
    session属性: (a2.jsp)
                缺省值是true,如果值是false,则容器不再添加获得
                session对象的代码了,也就是说,不能够使用session
                隐含对象了。
    errorPage属性: (a3.jsp)
                用来指定一个异常处理页面,当jsp运行发生异常,则容器
                会调用异常处理页面。
    isErrorPage属性:(a4.jsp)
                缺省值是false,如果值是true,就可以使用exception
                隐含对象了。
                注:
                    exception对象用于获得异常的一个简短的描述。

d.include指令
    
    file属性:用于指定被包含的文件名。
    注:
        容器会将file属性指定的文件的内容插入到该指令所在的位置。
        被包含的jsp并不会真正执行(没有对应的servlet)。

e.taglib指令

### 4)隐含对象
a.什么是隐含对象?

    在jsp里面可以直接使用的对象。

b.为什么可以直接使用这些隐含对象?
    
    因为容器会添加获得这些隐含对象的代码。

c.有哪一些隐含对象?

    c1. out
    c2. request
    c3. response
    c4. session
    c5. application (servlet上下文)
    c6. exception (只有当page指令的isErrorPage属性值为true时才能用)
    c7. pageContext(页面上下文)
        c1. pageContext是什么?
            容器会为每一个jsp实例创建唯一的一个符合PageContext
            接口要求的对象,该对象我们可以称之为页面上下文。
            注:
                只要jsp实例还在,pageContext就会一直存在。

        c2. 作用1 绑订数据 (a5.jsp,a6.jsp)
            注:
                绑订到pageContext上的数据,只有对应的jsp实例能够
                访问。类似“钱包”。
            作用2 提供了一些方法用来获得其它所有的隐含对象。
    c8. config (a7.jsp  ServletConfig)
        
![](s2.png)    

    
    c9. page: jsp实例本身。
        注:
            jsp实例是jsp对应的servlet对象。
    
### 5)注释 (a8.jsp)
a. <!-- 注释内容 -->

    注:
        如果注释的内容是java代码,java代码会执行。

b. <%-- 注释内容 --%>

    注:
        如果注释的内容是java代码,java代码不会执行。
    

## (3)jsp是如何执行的?
step1.容器要将jsp转换成一个Servlet:  

    html(css,js)  ------> service方法里面,使用out.write输出。
    <%    %>      ------> service方法里面,照搬。
    <%=   %>       ------> service方法里面,使用out.print输出。
    <%!   %>      ------> 给Servlet添加新的属性或方法。


step2.容器再去调用该Servlet:

    容器会将该Servlet先编译,然后实例化、初始化、调用、销毁。
**************************************************************************    

# 4.jsp标签和el表达式
## (1)什么是jsp标签?
jsp标签类似于html标签,用于替换jsp文件中的java代码,使用jsp标签,
可以简化jsp文件,便于代码的复用,并且也利于jsp文件的维护。

    注:
        如果将包含有java代码的jsp文件给美工去修改就很不方便。
    
## (2)什么是el表达式
一套简单的运算规则,用于给jsp标签的属性赋值,也可以脱离jsp标签直接使用。

## (3)el表达式的用法
### 1)读取bean的属性值
    注(了解)
        如果一个java类满足如下几个条件,可以称之为一个javabean。
        public class
        public 构造器
        最好实现Serializable接口
        有一些属性以及对应的get/set方法

a.方式一  ${user.username}  (e1.jsp)

    注:
        a1.执行过程:
             容器会依次从pageContext-->request-->session
            -->application中查找绑订名为"user"的对象(即调用
            getAttribute方法),找到该对象之后,会调用该对象的
            "getUsername"方法,然后输出该方法的返回结果。
        a2.优点:
             将null转换成""输出。
             如果找不到该对象,会输出"",不会报空指针异常。
        a3.可以指定查找范围:
            可以使用pageScope、requestScope、sessionScope、
            applicationScope来指定查询范围,比如
            ${sessionScope.user.username}。

b.方式二  ${user['username']} (e1.jsp)
        
    注:
        b1.[]里面可以出现绑订名。
        b2.[]里面可以出现从0开始的下标,用于读取数组中指定下标的
        某个元素的值。


******************************************************************

***********************
*------day12------*
************************

# 1. 使用el表达式进行一些简单的运算 (e1.jsp)
## (1)算术运算
+,-,*,/,%

    注:
        "+" 只能求和,不能够连接字符串。

## (2)关系运算
>,>=,<,<=,==,!=

## (3)逻辑运算
&&,||,!

## (4)empty
empty 运算:用于判断一个集合内容是否为空,或者是否为一个空字符串。
以下四种情况,运算结果都为true。

    a.集合内容为空。
    b.空字符串。
    c.null。
    d.找不到对应的值。

# 2.使用el表达式读取请求参数值 (e2.jsp)
a.${param.username}等价于
request.getParameter("username");

b.${paramValues.city}等价于
request.getParameterValues("city");

# 3.获得应用名
${pageContext.request.contextPath}
等价于
request.getContextPath();

# 练习 使用el表达式输出员工对象的各个属性值。
Employee类(ename,salary,age)


# 3.jstl (java standard tag lib)
## (1)jstl是什么?
apache开发的一套jsp标签,后来捐献给了sun,sun将其命名为jstl。

## (2)如何使用jstl?
step1.导包(jstl)。

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

step2.使用taglib指令导入要使用的jsp标签。

    <%@ taglib uri="" prefix=""%>
    
    uri: 指定jsp标签的命名空间。
        注:
            命名空间:为了区分同名的元素而在元素前添加的一个限定,
                通常是一个域名。
    prefix:指定命名空间的别名。

## (3)if标签  (c1.jsp)
1)语法
    
    <c:if test="" var="" scope="">
        标签体
    </c:if>

2)作用:
    相当于一个if语句,当test属性值为true时,容器会执行标签体的内容。
    test属性可以使用el表达式来计算。
    var属性用于指定绑订名,scope属性指定绑订的范围("page","request",
    "session","application")。

![](s1.png)

## (4)jsp标签的执行过程
容器依据标签的命名空间找到标签的描述文件(.tld文件),然后依据
标签的名称找到标签类,接下来,容器会将标签类实例化并调用该实例的
相应方法。

## (5)choose标签  (c2.jsp)
1)语法

    <c:choose>
        <c:when test="">
        </c:when>
        ...
        <c:otherwise>
        </c:otherwise>
    </c:choose>

2)作用

    相当于if..else if..else语句。其中,when标签可以出现1次或者多次,
    相当于一个if语句,otherwise标签可以出现0次或者1次,相当于最后
    那个else语句。
    当test属性值为true,执行标签体的内容,可以使用el表达式来赋值。

## (6)forEach标签 (c3.jsp)
1)语法
    <c:forEach items="" var="" varStatus="">
    </c:forEach>

2)作用
    
    用于遍历集合或者数组,其中,items属性用于指定要遍历的集合或者数组,
    可以使用el表达式来赋值。
    var属性用于指定绑订名,绑订的范围固定是pageContext,绑订值是集合
    或者数组中的某个元素。
        注:
            该标签每次从集合或者数组中取一个元素,然后将该元素绑订到
        pageContext上。
    varStatus属性用于指定绑订名,绑订的范围固定是pageContext,绑订
    值是一个特殊的对象,该对象由该标签提供,可以通过该对象获得当前遍历
    的状态。
        注:
            这个特殊的对象,提供下以下几个方法
            getIndex() :  获得当前正在被遍历的元素的下标(从0开始)。
            getCount() :  获得当前是第几次迭代(从1开始)。


# 4.自定义标签 (了解)
step1. 写一个java类,继承SimpleTagSupport类。

    注:
        jsp标签有两个版本,早期版本称之为复杂标签技术,新的
    版本称之为简单标签技术。

step2. override doTag方法,在该方法里写上处理逻辑。

    /**
     * 标签类
     *     注:
     *        标签有哪些属性,对应的标签类也必须有相应的
     *        属性(属性名要相同,类型要匹配,并且要有对应的
     *        set方法)。
     */
    public class HelloTag extends SimpleTagSupport{
    
    private String info;
    private int qty;
    
    public HelloTag() {
        System.out.println("HelloTag的构造器");
    }
    
    public void setInfo(String info) {
        System.out.println("HelloTag的setInfo方法...");
        this.info = info;
    }

    public void setQty(int qty) {
        System.out.println("HelloTag的setQty方法...");
        this.qty = qty;
    }

    @Override
    public void doTag() throws JspException, IOException {
        System.out.println("HelloTag的doTag方法...");
        /*
         * 通过继承自SimpleTagSupport类提供的
         * 方法来获得pageContext。
         * pageContext提供了用来获得其它所有隐含对象
         * 的方法。
         */
        PageContext pctx =
                (PageContext)getJspContext();
        JspWriter out = pctx.getOut();
        
        for(int i = 0; i < qty; i ++){
            out.println(info + "<br/>");
        }
        }
    }

step3. 描述标签(.tld文件)


***********************
*------day13------*
************************    

# 1.自定义标签 (了解)
step1. 写一个java类,继承SimpleTagSupport类。

    注:
        jsp标签有两个版本,早期版本称之为复杂标签技术,新的
    版本称之为简单标签技术。

step2. override doTag方法,在该方法里写上处理逻辑。

    /**
     * 标签类
     *     注:
     *        标签有哪些属性,对应的标签类也必须有相应的
     *        属性(属性名要相同,类型要匹配,并且要有对应的
     *        set方法)。
     */
    public class HelloTag extends SimpleTagSupport{
    
    private String info;
    private int qty;
    
    public HelloTag() {
        System.out.println("HelloTag的构造器");
    }
    
    public void setInfo(String info) {
        System.out.println("HelloTag的setInfo方法...");
        this.info = info;
    }

    public void setQty(int qty) {
        System.out.println("HelloTag的setQty方法...");
        this.qty = qty;
    }

    @Override
    public void doTag() throws JspException, IOException {
        System.out.println("HelloTag的doTag方法...");
        /*
         * 通过继承自SimpleTagSupport类提供的
         * 方法来获得pageContext。
         * pageContext提供了用来获得其它所有隐含对象
         * 的方法。
         */
        PageContext pctx =
                (PageContext)getJspContext();
        JspWriter out = pctx.getOut();
        
        for(int i = 0; i < qty; i ++){
            out.println(info + "<br/>");
        }
        }
    }

step3. 描述标签(.tld文件)

    <tag>
    <name>hello</name>
    <tag-class>tag.HelloTag</tag-class>
    <!--
        设置标签体的内容。
        有三个值:
        empty:
             该标签没有标签体。
        scriptless:
             该标签有标签体,但是,在标签体里面,不能够
             出现java代码(<% %>,<%= %>,<%! %>)
        JSP:
            该标签有标签体,并且,标签体里面可以出现
            java代码。但是,只有复杂标签才支持该值。
     -->
    <body-content>empty</body-content>
    <attribute>
        <name>info</name>
        <!--
            如果值为true,表示该属性必选。
         -->
        <required>true</required>
        <!--
            如果值为true,表示该属性可以动态赋值
            (可以使用el表达式来赋值)。
         -->
        <rtexprvalue>false</rtexprvalue>
    </attribute>
    <attribute>
        <name>qty</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>


# 2.MVC (Model,View,Controller)
## (1)MVC是什么?
是一种软件架构思想、其核心思想是:在设计一个软件时,应该将数据处理与
数据展现分开,按照这种思想,可以将一个软件划分成三种不同类型的模块,
分别是模型、视图和控制器。

其中,模型负责数据处理(封装业务逻辑),视图负责数据展现(表示逻辑)、
控制器负责协调模型和视图(请求先发送给控制器,由控制器选择对应的模型
来处理;模型将处理结果要交给控制器,由控制器选择对应的视图来展现)。

## (2)如何使用MVC?
在开发一个web应用时,可以使用java类来充当模型、使用Servlet来充当
控制器,使用jsp来充当视图。
![](mvc.png)

## (3)MVC的优点
a.将数据处理与数据展现分开,处理结果可以使用不同的方式来展现。

b.方便测试。

    注:
        比如,将业务处理逻辑写在Servlet里面,需要部署整个应用才能
    测试,如果将业务逻辑写在java里面,就可以直接测试。

c.方便分工协作。

d.方便代码的维护。

## (4)MVC的缺点
使用mvc,会增加代码量,会增加软件设计的难度,相应会增加软件的成本。
所以,只有具有一定规模,并且强调软件的可维护性的情况下,才需要使用
MVC。


# 练习
将用户管理(day12-lab)中的所有jsp移到WEB-INF下。






    

    























    
    


        

    



        
    








 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值