JavaWeb项目

开发JavaWeb的程序,必需要严格参照JavaWeb提供的规范来存放我们的资源。结构分析如下:

JavaWeb项目结构

  1. WEB-INF里面的程序是不可见的,必需通过我们的程序访问;

  2. 现在web.xml并不是必需的;如果项目中需要用到这个web.xml,建议可以从apache-tomcat-xxx\webapps\ROOT\WEB-INF\web.xml拷贝;

  3. index是非常特殊的,我们访问到一个文件夹,如果没有确定是哪一个文件,它就会去找名称为index.html或者index.jsp的文件;

部署流程

  1. 创建一个文件夹oa;

  2. 在oa下面创建WEB-INF文件夹,在WEB-INF下面分别创建lib和classes文件夹;

  3. 拷贝web.xml到WEB-INF下面。可以从\apache-tomcat-xxx\webapps\ROOT\WEB-INF\web.xml拷贝;

  4. 在oa文件夹下面创建一个hello.html;

  5. 直接把文件夹放到Tomcat的webapps中

  6. 在server.xml里面进行配置

<!--
 docBase:项目的路径
 path:项目访问的虚拟路径(可以为/代表没有)
 -->
<Context docBase="D:/oa" path="myoa" />

注1:项目需要部署(将项目就交给tomcat保管)才能访问,以上两种部署方式:第一种将整个WebContent文件夹拖到tomcat的webapps下(不推荐,一般开发完项目可以这样做)。第二种使用server.xml配置(方便开发)。

注2:直接访问域名+端口号会根据apache-tomcat-xxx\webapps\ROOT\WEB-INF\web.xml配置文件中的<welcome-file-list>标签中的顺序匹配

Servlet相关

Servlet是一个接口,一个规范(sun公司并没有去实现它),它的实现就是由各大服务器厂商(Tomcat)去实现;Tomcat是一个javaweb服务器,也是一个Servlet容器;Servlet容器是管理所有Servlet对象的创建,运行,销毁的容器。而Servlet对象也只有在Servlet容器中才能使用。所以如果写了一个Servlet, 那么一定要记住,把这个Servlet交给Tomcat去管理

Servlet部署流程

  1. 访问之前一定要确保Tomcat服务要开启,并且要将项目部署到Tomcat,否则出现404错误;

  2. 用户在浏览器端输入地址。例如:http://localhost:80/servlet/hello 该请求访问的是本地(localhost)端口号为80的程序,即tomcat;

  3. Tomcat会到webapps中去找到servlet这个程序或者到server.xml中根据上下文路径<Context>中的找到对应的项目

  4. 然后Tomcat会去找到该项目的配置文件web.xml,然后查看有没有hello这个请求;

  5. 请求:http://localhost:80/servlet/hello

    :当我们找到这个 /hello 的时候,也就相应的找到了Servlet的名字(servlet-name) : hello

  6. Tomcat会根据请求hello去匹配web.xml中的<url-pattern>中的值:

    • 如果没有匹配上就去找这个项目默认web路径下有没有hello这个页面(html或jsp):

      如果没有,404;

      如果有这个页面,显示页面的内容;

    • 如果匹配上了会根据<Servlet-name>标签找到相应的Servlet类:

  7. 找到相应的类之后,到缓存区里面去看这个类有没有相应的实例:

    • 如果没有,通过反射创建一个实例,并将这个实例放到缓存区:

      执行构造方法

      执行初始化方法

    • 如果有,直接拿到这个实例;

  8. 调用实例的service方法执行业务逻辑处理;

  9. 如果正常关闭的话,会执行destroy方法,必须要初始化了servlet才会执行destroy方法;

Servlet执行流程

Servlet生命周期

  1. Servlet容器调用无参构造创建对象:第一次访问 或 项目部署的时候
  2. Servlet容器调用初始化方法init() :第一次访问 或 项目部署的时候
  3. Servlet容器调用服务方法service()doGet()doPost():第n次访问
  4. 对于Tomcat来说,Servlet只有一个(它是单例的,每次创建的Servlet实例都会缓存起来)
  5. 当我们正常关闭Tomcat的时候,Servlet容器会自动调用销毁方法destory()
  6. 构造方法 –> init方法 –> service【每次请求都会执行】 –> destory【正常关闭才执行】

servlet的执行流程

Servlet的实现方式

有两种实现方式:

第一种是实现Servlet接口,重写其中的所有方法;第二种是继承服务器重写Servlet接口的实现类,例如Tomcat中的HttpServlet

public class SecondServlet extends HttpServlet{
 	@Override
 	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 		//写功能代码
 	}
}

处理请求的方式

处理请求的方式

Get请求与Post请求的区别:

  1. get请求时,请求参数放在请求地址url后面,而post提交方式时,请求参数是放在请求数据包中的实体内容中传递

  2. 由于地址栏的数据有长度限制,所以Get请求传输的数据量小,一般不能大于2kb,Post请求传输的数据大小没有限制。所以一般文件上传下载使用的是Post请求;

  3. Post安全性相对Get较高;

  4. get请求的发送时间:

    • 直接输入网址
    • 点击链接
    • 设置表单的提交方式为get或表单的默认提交

    post请求的发送时间:

    • 设置表单提交方式为post(method="post")

HttpServlet中的Request与Response对象

HttpServletRequest

HttpServletRequest对象是Servlet的请求对象,可以获取请求数据包/报文中的所有信息。

常用方法:

String getContextPath()获取上下文路径,<Context path="上下文" ../>

String getHeader(String headName)根据指定的请求头获取对应的请求头的值;

String getRequestURI()返回当期请求的资源路径URI(上下文路径/资源名);

StringBuffer getRequestURL()返回浏览器请求地址URL;

String getRemoteAddr()返回请求服务器的客户端的IP;

String getServletPath()返回请求,<url-pattern>中的值;

String getParameter(String name)根据参数名称,获取对应参数的值;

String[] getParameterValues(String name)根据参数名称,获取该参数的多个值;

Map<String,String[]> getParameterMap()返回请求参数组成的Map集合;

void req.setCharacterEncoding("UTF-8")能够正确获取post请求的中文参数而不出现乱码;

String getProtocol()获取协议版本HTTP/1.1

String getMethod()获取请求方式(GET or POST)

int getServerPort()获取端口号

HttpServletResponse

HttpServletResponse对象是Servlet的响应对象,可以设置响应的文件格式和编码格式,还可以获取输出流。

常用方法:

OutputStream getOutputStream()获取流的方法一,获取字节输出流(上传下载用)

resp.getWriter()获取流的方法二,获取字符输出流(字符输出用此流,向页面输出)

resp.setContentType("text/html;charset=UTF-8")响应页面的文件格式和编码格式

乱码问题

  1. 向页面输出中文

    resp.setContentType("text/html;charset=utf-8")能够向页面输出中文,""中的内容不要写错,否则浏览器不认识响应的类型,就会将问题抛给用户;

  2. 获取表单提交的中文数据

    针对post请求(请求参数是在实体内容中)

    第一种:req.setCharacterEncoding("utf-8")必须写在获取参数前,因为如果获取了参数,设置编码无效

    第二种:name = new String(name.getBytes("iso-8859-1"), "utf-8");转码,缺点:太麻烦,每个数据都要转

    :两种只能用其一。

  3. 针对get请求(请求参数是在地址栏上),tomcat8不做处理,如果是tomcat7及其以前:

    第一种:name = new String(name.getBytes("iso-8859-1"), "utf-8");转码

    第二种:修改服务器中的配置conf – server.xml – <Connector>标签中最后加上属性URIEncoding="utf-8"

    :两种只能用其一 ,以后服务器换了,还需重新配置一次;

  4. 注意:

    • tomcat8.x之前的默认编码集为ISO-8859-1,tomcat8.x之后默认编码集为UTF-8;

    • 对于tomcat8.x以及之后的get请求不需要转码或配置,而Tomcat7需要配置;

    • 做项目的时候,项目部署不一定是tomcat,在不能修改web服务器的状态下,可以通过过滤器来解决;

Servlet细节

url-pattern的多种匹配方式

  1. 精确匹配配置什么就必须写什么,精确匹配中/不能少

    方式一:在一个<servlet-mapping>中配置多个<url-pattern></url-pattern>

    方式二:在一个Servlet中可以配置配置多个<servlet-mapping></servlet-mapping>

  2. 通配符匹配/*

    方式一:通配符匹配:可以拦截到所有的请求

    方式二:以指定路径开始的匹配,例如:/system/*、/system/user/* 很多时候,我们做权限,就会用到这个拦截

  3. 后缀匹配(*.后缀名

    以后缀的方式匹配,注意后缀匹配是没有加/

    例如:*.action*.do*.user*.student*.admin等等,此方式不能加/

    :后缀匹配中不要配置*.html和*.jsp后缀(与页面的后缀冲突),后缀请求匹配会先匹配web.xml或注解直接找到Servlet,而不会请求对应的html和jsp页面

初始化配置

  1. 为了提高第一次访问Servlet的效率,可以将Servlet实例化初始化的时机提前到项目部署的时候,只需要加上<load-on-startup></load-on-startup>即可

  2. <load-on-startup></load-on-startup>里面的数字代表就是servlet创建的先后顺序,数字越小,越早启动

  3. <servlet-name>不能取名叫做default,默认的default对应的servlet就是访问静态资源,如果servlet名字叫做default会把别的功能覆盖掉

注解方式

通过传统方式每配置一个servlet就需要写一大段的配置信息,所以servlet给我们提供了注解的形式。

通过@WebServlet("/暴露路径"),将此注解加在servlet控制器类上,就可以代替我们之前的配置,配置方式:如果只有一个路径名称那么可以不加,但是*.xxx除外。

例如:@WebServlet("/mapping")@WebServlet(urlPatterns={"/mapping","/mapping2","/mapping3"})@WebServlet(urlPatterns={"/system/user/*"})@WebServlet(urlPatterns={"*.xxx"})@WebServlet("/*")

线程安全

Servlet是单例的(同一个线程发送多次请求,只会创建一个对象)。但是Servlet是线程不安全的。当多个线程同时访问同一个成员变量时,若其中一个线程修改了成员变量的值,则会出现线程安全问题。

解决方法一:

实现SingleThreadModel接口,这个方法SingleThreadModel相当于一个把锁,必须等第一个线程计算完,之后线程才进来,这样导致效率低下。

解决方法二:

避免写成员变量。

注:Servlet和Springmvc都是非线程安全的(不要写成员变量);Struts2是线程安全的(可以写成员变量)。

合并Servlet

如果涉及到一个表中有多个请求(CRUD等),可以将多个Servlet合并为一个。

有三种合并方式:

  1. 使用后缀匹配*.表名实现,后台判断请求的uri区分不同的请求,调用不同的方法处理;
  2. 在表单中使用隐藏域,每个请求写不同的值,后台获取这个隐藏域参数之后再判断,然后调用不同的方法处理;
  3. 在请求路径后面跟上一个特定参数,后台以这个参数来判断是要执行什么操作。
/**
 * dept页面的servlet
 * 主要功能:
 * 展示数据,增加部门,修改部门,删除部门
 * @author bruises
 */
@WebServlet("/dept/*")
public class DeptServlet extends HttpServlet {
    /**
     * 获取一个私有化的dept的service层对象
     */
    private DeptService deptService = new DeptServiceImpl();

    /**
     * 重写HttpServlet类中的doGet方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置请求内容的字符集
        req.setCharacterEncoding("utf-8");
        // 请求过来的路径path
        String uri = req.getRequestURI();
        String path = uri.substring(uri.lastIndexOf("/")+1);
        // 判断请求类型
        switch (path) {
            case "list":
                doList(req,resp);
                break;
            case "add":
                doAdd(req,resp);
                break;
            case "update":
                doUpdate(req,resp);
                break;
            case "update_save":
                doSave(req,resp);
                break;
            case "delete":
                doDel(req,resp);
                break;
            default:
                break;
        }
    }
    /**
     * 重写HttpServlet类中的doPost方法,设置了输出内容字符集后,直接调用doGet业务逻辑
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        doGet(req,resp);
    }

    /**
     * 查询全量Dept数据的方法,私有化,仅允许doGet与doPost方法调用
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    private void doList(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Dept> listDept = deptService.findAllDept();
        req.setAttribute("listDept",listDept);
        req.getRequestDispatcher("/WEB-INF/dept.jsp").forward(req,resp);
    }

    /**
     * 获取用户新增的数据,并新增
     * @param req
     * @param resp
     */
    private void doAdd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String manager = req.getParameter("manager");
        String tel = req.getParameter("tel");
        String num = req.getParameter("num");
        Dept dept = new Dept(name, manager, tel, Integer.valueOf(num));
        deptService.add(dept);
        doList(req,resp);
    }

    /**
     * 删除部门的方法
     * @param req
     * @param resp
     */
    private void doDel(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Integer id = Integer.valueOf(req.getParameter("id"));
        deptService.del(id);
        doList(req, resp);
    }

    /**
     * 修改部门数据前,查询并展示部门的方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    private void doUpdate(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Integer id = Integer.valueOf(req.getParameter("id"));
        Dept dept = deptService.findById(id);
        req.setAttribute("dept",dept);
        req.getRequestDispatcher("/dept_edit.jsp").forward(req,resp);
    }

    /**
     * 将前端数据读取并修改部门数据的方法
     * @param req
     * @param resp
     */
    private void doSave(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Integer id = Integer.valueOf(req.getParameter("id"));
        String name = req.getParameter("name");
        String manager = req.getParameter("manager");
        String tel = req.getParameter("tel");
        String num = req.getParameter("num");
        Dept dept = new Dept(id, name, manager, tel, Integer.valueOf(num));
        deptService.update(dept);
        doList(req,resp);
    }
}

Servlet交互

Servlet的三大职责

  1. 接收请求参数(封装)

  2. 调用业务方法处理业务(去调用业务service层)

  3. 响应请求(跳转页面或其他Servlet)

用户登陆跳转逻辑图

跳转和数据共享的原因

  • 跳转:需要做责任分离(Servlet擅长写代码即处理业务逻辑,jsp擅长展示页面);

  • 共享:Http是无状态的,我们跳转的时候数据无法传递,因此需要做数据共享。

跳转

跳转的目标有两种:Servlet跳转其它资源(例如:jsp,html)或者 Serlvet跳转其他Servlet

跳转有两种方式:请求转发与重定向

重定向与转发

请求转发Forward

转发的方式:req.getRequestDispatcher("路径").forward(request, response)

特点:

  • 请求只有一次,不会发起多次请求
  • 浏览器请求地址不会改变
  • 多次转发之间获取到的参数是一样的
  • 可以访问受保护的资源
  • 只能转发到内部请求,不能访问别人的服务器,不能跨域
  • 只有最后一个response会生效
  • 即便请求转发走了,后面的代码还是会执行

使用场景:

  1. 如果想要多个servlet之间共享数据,那么使用请求转发
  2. 如果想要访问WEB-INF下面的资源,那么使用请求转发
  3. 查询完列表之后,使用请求转发,转发到列表界面,方便取值

重定向Redirect

重定向跳转的方式:resp.sendRedirect("路径")

特点:

  • 地址栏会发生变化
  • 会发送多次请求
  • 由于重定向是多次请求,所以多个servlet之间不能共享数据
  • 无法访问受保护的资源
  • 可以跨域访问
  • 每个response都会生效,但是只能看到最后一个,可以通过代码看到是生效了
  • 即便重定向走了,还是会执行后续的代码

使用场景:

  1. 如果想要跨域访问,那么使用重定向
  2. 做数据的添加、删除、修改操作,使用重定向,因为请求转发可能会造成多次重复提交问题
请求转发(forward) 重定向(redirect)
访问 WEB-INF ×
传参数 ×
访问外网 ×
重复提交的问题
路径变化
代码 req.getRequestDispatcher(path).forward(req, resp); resp.sendRedirect(path)

JSP相关

为了将Servlet中用于表现的部分分离出来,Java使用JSP实现。JSP(java server page)即java服务器端(动态)网页,JSP就是Java中用来做动态网页的技术,既然是页面,对于前端代码编写人员来说,可以当成html页面来进行渲染工作。JSP底层就是一个Servlet,在执行的时候先转成Servlet然后同样要经历Servlet的生命周期,Servlet主要是处理业务为主(Java后台代码),JSP主要以表现为主(HTML,CSS,JS等前端代码),Servlet更擅长逻辑的编写,JSP更擅长于数据的显示,最后达到一个目标,servlet里面不要写HTML代码,jsp里面不要写java代码。

JSP原理分析

JSP原理分析

  1. 浏览器第一次访问 hello.jsp 页面,会去找到conf目录web.xml里面*.jsp,在会找到JspServlet

  2. tomcat 会将 hello.jsp 转换为名为 hello_jsp.java 的一个 Servlet存储在tomcat目录下work\Catalina\localhost\ROOT\org\apache\jsp路径

  3. tomcat 再将转换的 servlet 编译成字节码文件 hello_jsp.class

  4. tomcat 会执行该字节码文件,向外提供服务

语法

  1. 注释:<%--这是注释--%> 在jsp翻译成Servlet的时候这个注释就没有了,源代码看不到

  2. JSP表达式:

    语法:<%=表达式%>(实际上就是调用输出流打印到页面上 out.print(表达式)

    作用:输出数据到页面上

    例子:<%=new java.util.Date().toLocaleString() %>转化成Java代码:转换到自动生成Servlet的_jspService方法中out.print(new java.util.Date ().toLocaleString());

  3. JSP申明:

    语法:<%! Java代码 %>

    作用:定义成员

    转化成Java代码:转换成自动生成的Servlet类中的成员

  4. JSP脚本:

    语法:<% Java语句1;Java语句2;%>

    作用:编写Java逻辑代码;

    转化成Java代码:转换到自动生成Servlet的_jspService方法中;

JSP指令

JSP指令有三种:page(页面指令)、include(包含指令)、taglib(标签指令(JSTL))

  • page指令

    格式:<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" ... >

    属性:

    language="java"语言只有java,意义不大

    contentType="text/html; charset=UTF-8"输出的页面类型,相当于在Servlet里面写resp.setContentType(“text/html;charset=utf-8”)`

    pageEncoding="UTF-8"

    errorPage="/myerror.jsp" 如果当前页面出错,就跳转到对应的页面

    hello.jsp指定errorPage="/myerror.jsp"

    isErrorPage="true"这个页面是否是错误页面(当要在页面上直接使用exception的时候就可以加上该属性)

  • include指令

    当每个页面都有导航的时候,只需要使用一个,这个时候就可以使用包含指令。

    ![JSP指令- include指令](/JSP指令- include指令.jpg)

作用域对象

在做数据共享的时候,会把数据放到不同的地方。这个不同的地方就是放到不同的作用域里面,作用域对象有四个,JSP四大作用域对象属于9大内置对象里面的,用来共享或传递数据的。作用域有大小,存在哪个作用域对象里,就需要在哪个作用域对象中去取得,即不能跨域获取值。

对象(叫法) 范围
PageContext pageContext 当前页才能使用,作用不大,值直接使用就是,根本不需要在放到对象里面
HttpServletRequest request 一次请求(必需请求转发)
HttpSession session(多个对象) 一次会话(只要浏览器或服务器任意一端断开则会话结束)
ServletContext application(上下文对象) 整个应用(有且只有一个对象)

作用域范围

  • 对象获取:

    request就是通过请求获得的request对象

    session是通过request.getSession()获取session对象

    application,有四种获取方式:

    1. 第一种是通过request获取,ServletContext application = getServletContext(); 或者 req.getServletContext();
    2. 第二种是通过super获取,ServletContext app1= super.getServletContext();
    3. 第三种是通过ServletConfig对象获取,super.getServletConfig( ) .getServletContext();
    4. 第四种是通过session获取,req.getSession() .getServletContext();
  • 语法:

    • 拿到作用域中共享后的数据:作用域对象.getAttribute("key")
    • 设置作用域中数据:作用域对象.setAttribute("key","value")
    • 删除作用域中数据:作用域对象.removeAttribute("key")
    • 修改作用域内数据(重新放一次,设置一个相同的key)作用域对象.setAttribute("key","value")
  • ServletContext对象的常用方法:

    getContextPath(); 拿到上下文路径

    getRealPath("/"); 拿到真实路径(以后做上传下载可以使用)

    getInitParameter("encoding"); 拿到初始化参数(只能拿到全局里面的参数信息)

缺点

由于 JSP页面内,既可以定义 HTML 标签,又可以定义 Java代码,造成了以下问题:

  1. 书写麻烦:特别是复杂的页面,既要写 HTML 标签,还要写 Java 代码
  2. 阅读麻烦:可读性差,html和java代码混合
  3. 复杂度高:运行需要依赖于各种环境,JRE,JSP容器,JavaEE…
  4. 占内存和磁盘:JSP会自动生成.java和.class文件占磁盘,运行的是.class文件占内存
  5. 调试困难:出错后,需要找到自动生成的.java文件进行调试
  6. 不利于团队协作:前端人员不会 Java,后端人员不精 HTML
  7. 如果页面布局发生变化,前端工程师对静态页面进行修改,然后再交给后端工程师,由后端工程师再将该页面改为 JSP 页面

由于上述的问题, JSP 已逐渐退出历史舞台,以后开发更多的是使用 HTML + Ajax 来替代。有Ajax这个技术后,前端工程师负责前端页面开发,而后端工程师只负责后端代码开发。

EL表达式

EL(Express Language)就是一种表达式语言,可以获取四大作用域中的共享数据,优化了JSP语法中的语句。EL表达式获取作用域中的属性要依靠JavaBean的可读属性即需要有getter方法,否则无法获取。

语法

  • 获取作用域中的属性:使用${key} 获取,会到依次从四个作用域里面去找到key对应的value,先取小的范围的值,小的没有,在取到大的范围的值,如果key不存在,显示为空字符串,而不会显示null值

    如果两个作用域都存在需要取的key,则需要在取值时使用作用域Scope.key,例如 ${requstScope.msg}

    如果在设置属性值时有特殊字符,例如KEY.IN.SESSION则在获取时需要用${sessionScope["KEY.IN.SESSION"]}获取

    <%-- JSP语句写法 --%>
    <%= request.getAttribute("error")==null?"":request.getAttribute("error") %>
    
    <%-- EL表达式 --%>
    ${error}
    
  • 访问JavaBean中的属性:用${对象名.属性名}获取,如果属性名有特殊字符,则通过 ${对象名[“属性名”]} 获取。其中对象名可以从四大作用中获取,而对象名写错会显示空字符串,属性名写错会报错。

    // java代码中new一个对象
    User user = new User(1L,"张飞","123");// 属性分别为id,ueserName,password
    
    <%-- 获取user对象的JavaBean属性 --%>
    <p>
    id:${user.id}<br>
    user_name:${user.userName}<br>
    password:${user.password}<br>
    </p>
    
    <%-- 拿到上下文路径,页面上的href,src等属性可以使用这种方式制定绝对路径 --%>
    ${pageContext.request.contextPath} 
    <%-- 例如 --%>
    <a href="${pageContext.request.contextPath}">XXX</a>
    
  • EL运算符:

    <%-- 算数运算符 --%>
    ${1+2} ${2-1} ${2*3} ${16/5}
    <%-- 关系运算符 --%>
    ${16>5}	或	${16 gt 5}
    ${1==2}	或	${1 eq 2}
    <%-- 逻辑运算符 --%>
    ${true && true} 或 ${true and true}
    ${!true} 或 ${not true}
    <%-- 三目运算符 --%>
    ${A?B:C}
    <%-- 其他运算符 --%>
    ${empty param.name} 如果param.name 为空返回true否则false
    

JSTL相关

JSTL(JavaServer Pages Standard Tag Library)JSP标准标签库,标签库由标签库和EL表达式语言两个部分组成,用来消除JAVA代码

使用

  1. 导包 jstl.jar 和 standard.jar

  2. 引用JSTL标签库

    标签库 URL 前缀 使用模式
    核心标签库 http://java.sun.com/jstl/core c <c:tagname>
    国标化标签(I18N) http://java.sun.com/jstl/fmt fmt <fmt:tagname>
    SQL标签库 http://java.sun.com/jstl/sql sql <sql:tagname>
    XML标签库 http://java.sun.com/jstl/xml x <x:tagname>
    函数标签库 http://java.sun.com/jstl/functions fn <fn:tagname>
  3. 在使用的jsp文件中导入使用语句,例如<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

常用标签

if标签

<%
		request.setAttribute("age",16);
%>
<c:if test="${age > 18}">
  	age is greater than 18
</c:if>
<c:if test="${age < 18}">
  	age is less than 18
</c:if>

foreach标签

<c:forEach items="${users}" var="user" varStatus="s">
		${s.count} |||| ${user.id}--${user.username}--${user.password}<br>
</c:forEach>
  1. items:要循环的集合或数组,必须通过el表达式获取作用域中的数据
  2. var:用于接收集合中的每一个对象
  3. varStatus:当前循环的状态,它是个javabean
    • index:循环索引,从0开始,相当于我们for循环的下标
    • count:计数,从1开始,计算遍历了几次,跟下标的区别是他只能每次增加1
    • last:是否是最后一次,只有最后一次的时候才是true
  4. begin:表示从那里开始展示,从0开始
  5. end:表示从那里结束展示
  6. step:步长,表示每次循环+几个

choose标签

<c:choose>
		<c:when test="${age <= 18}">
  			age is less than 18
  	</c:when>
  	<c:when test="${age > 18 && age <= 60}">
  			age is between 18 and 60
  	</c:when>
  	<c:otherwise>
  			age is greater than 60
  	</c:when>
</c:choose>