WEB应用之JSP+Servlet

开发网页基础知识

JSP(java server pages)(前端)

  • 动态网页开发技术。可以插入java代码,标签以<%开头 以>结束

  • 服务端语言,与PHP,SASP等类似。

  • jsp以java语言作为脚本语言,而且可跨平台使用。

  • 简单代码演示

<html>
    <head>
           <title>第一个 JSP 程序</title>
    </head>
    <body>
           <%
                  out.println("Hello World!");
           %>
    </body>
</html>
  • JSP优势
    • 动态部分用java编写,而不是VB或其他专用语言,所以更加强大,易用。
    • JSP可以方便的编写或者修改HTML网页而不用面对println()语句。
    • 可以使用表单提交数据,与数据库打交道。
 与ASP相比:JSP有两大优势。首先,动态部分用Java编写,而不是VB或其他MS专用语言,所以更加强大与易用。第二点就是JSP易于移植到非MS平台上。
与纯 Servlet 相比:JSP可以很方便的编写或者修改HTML网页而不用去面对大量的println语句。
与SSI相比:SSI无法使用表单数据、无法进行数据库链接。
与JavaScript相比:虽然JavaScript可以在客户端动态生成HTML,但是很难与服务器交互,因此不能提供复杂的服务,比如访问数据库和图像处理等等。
与静态HTML相比:静态HTML不包含动态信息。

JSP生命周期

  1. 编译阶段
    解析jsp,将jsp转为servlet,servlet容器编译servlet源文件,生成servlet类。
  2. 初始化阶段
    加载与jsp对应的servlet类,创建其实例,并调用初始化方法程序只初始化一次
  3. 执行阶段
    调用与jsp对应的servlet实例的服务方法
    4.销毁阶段
    调用与JSP对应的servlet实例的销毁方法,然后销毁servlet实例

JSP的两个请求(get,post)

  • 其实就是表单的请求
  • GET请求
    • 会把请求参数跟在地址之后
    • 例如:http://localhost:8080/test?参数名1=参数值1 & 参数名2=参数值2 …
    • 传递参数的长度有限
  • POST请求
    • 请求参数会包含在请求体内,对外不可见
    • 没有长度限制, 注意 post 并不是真正安全(并没有对参数做加密处理),可以F12查看post请求的具体内容,所以不是安全的。

JSP九个隐式对象

  1. request对象

    • request对象是javax.servlet.http.HttpServletRequest 类的实例。每当客户端请求一个JSP页面时,JSP引擎就会制造一个新的request对象来代表这个请求。
    • request对象提供了一系列方法来获取HTTP头信息,cookies,HTTP方法等等。
  2. response对象

    • response对象是javax.servlet.http.HttpServletResponse类的实例。当服务器创建request对象时会同时创建用于响应这个客户端的response对象。
    • response对象也定义了处理HTTP头模块的接口。通过这个对象,开发者们可以添加新的cookies,时间戳,HTTP状态码等等。
  3. out对象

    • 相应输出流。
  4. session对象

    • 会话对象
  5. application对象

    • application对象直接包装了servlet的ServletContext类的对象,是javax.servlet.ServletContext 类的实例。
    • 这个对象在JSP页面的整个生命周期中都代表着这个JSP页面。这个对象在JSP页面初始化时被创建,随着jspDestroy()方法的调用而被移除。
    • 通过向application中添加属性,则所有组成您web应用的JSP文件都能访问到这些属性。
  6. config对象

    • 用来读取和jsp配置相关的信息
  7. pageContext 对象

    • 页面作用域
    • 这个对象存储了request对象和response对象的引用。application对象,config对象,session对象,out对象可以通过访问这个对象的属性来导出。
      pageContext对象也包含了传给JSP页面的指令信息,包括缓存信息,ErrorPage URL,页面scope等。
  8. page 对象

    • 当前的jsp对象(this)
  9. exception 对象

    • 必须在当前页面的 page 指令中添加 isErrorPage=“true”, 表示一个异常对象。

JSP的网页如何编写参考菜鸟教程吧

菜鸟教程–JSP

Servlet(后端)

  • servlet是与JSP搭配使用的服务端程序,在后台管理数据,界面请求等等。
  • 在tomcat配置的时候写过一个helloworld的servlet代码
@WebServlet(urlPatterns = "/test")
public class MyServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().print("hello, world");
    }
}
  • 想要编写自己的servlet类有几个要求

    • 第一:需要继承一个HttpServlet的类,并且重写里面的方法,至于重写哪个方法,就得看个人需求了。在IDEA里ctrl+o,查看可重写的方法,一般情况都是重写service方法。
    • service方法带的两个参数,request和response。分别可以得到网页传递到servlet程序的参数信息,和向网页JSP页面发送一些参数信息。
    • 例如,在JSP页面打印“hello world”
    • 其次还要在servlet程序上加一个webservlet注解,并写上访问的路径。例如上述就是http://localhost:8080/test
  • 输出当前系统时间的例子

@WebServlet(urlPatterns = "/data")
public class MyServerlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset = utf-8");
        Date date = new Date();
        String html = "<html><body><h1>serverlet时间:"+ date+ "</h1></body></html>";
        resp.setHeader("Refresh","1");
        resp.getWriter().println(html);
    }
}
  • 说明
    • 有时候在jsp页面打印会出现乱码问题,可能是因为,IDEA和浏览器使用的不是统一的编码,浏览器大多数m默认utf-8,所以需要调用方法 resp.setCharacterEncoding(“utf-8”);

综合例子: JSP和Servlet交互配合数据库将数据存入数据库(理解整个过程)

  • 前端JSP页面编写
<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2019/1/6 0006
  Time: 17:07
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <script>  //在JSP页面可以编写一些脚本,使用script标签,可以放在head标签里,也可以放在body标签里
        function test1() {   //这个方法检测username的格式,相当于一个正则表达式
            var username = document.getElementById("us").value; //获取表单里username的值
            if (/^\w+$/.test(username)){  //要去必须实字母或者数字,并且有响应的提示
                document.getElementById("ustest").innerText = "格式正确";
                return true;
            }else {
                document.getElementById("ustest").innerText = "格式错误";
                return false;
            }
        }
        function test2() {  //这个方法检测密码的格式
            var password = document.getElementById("pa").value;
            if (/^\w+$/.test(password)){
                document.getElementById("patest").innerText = "格式正确";
                return true;
            }else {
                document.getElementById("patest").innerText = "格式错误";
                return false;
            }
        }
        function test3() {  //这个方法是只有username和password格式正确了返回一个true,否则返回flase,在表单的onsubmit方法,只有值为true时,表单才准许提交到服务端。
            if (test1()&&test2()){
                return true;
            } else {
                return false;
            }
        }
        //在用户名和密码调用的onblur方法,是鼠标从输入框离开时出发这个方法检测格式是否正确。
    </script>
</head>
<body>
    <form action="/myform" method="post" onsubmit="test3()">
        <p>用户名<input type="text" name="username"  id="us" onblur="test1()"><span id="ustest"></span></p>
        <p>密码 <input type="password" name="password" id="pa" onblur="test2()"><span id="patest"></span></p>
        <p><input type="submit" value="提交"> </p>
    </form>
</body>
</html>

  • 后端Servlet编写
数据库连接的工具类

import com.alibaba.druid.pool.DruidDataSource;

import java.sql.*;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @ClassName JDBCutils
 * @Author zhang-peng-zhan
 * @Date 2019/1/11 17:18
 */
public class JDBCutils {
    static final String url_user = "jdbc:mysql://localhost:3306/user" +
            "?rewriteBatchedStatements=true&useCursorFetch=true&defaultFetchSize=50&useSSL=false";
    static final String usename = "root";
    static final String password = "root";

    static final DruidDataSource dataSource = new DruidDataSource();
    static {
        dataSource.setUrl(url_user);
        dataSource.setUsername(usename);
        dataSource.setPassword(password);
//        dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 可选步骤,注册驱动
        dataSource.setInitialSize(5); // 初始连接数
        dataSource.setMaxActive(10); // 最大连接数
        dataSource.setMinIdle(5);    // 最小连接数
        dataSource.setValidationQuery("select 1"); // 一条简单的sql语句,用来保活
        dataSource.setTestWhileIdle(true); // 当空闲时时不时检查一下连接的有效性, 利用ValidationQuery中的sql语句
        dataSource.setTimeBetweenEvictionRunsMillis(60*1000); // 默认一分钟
    }
    // 获取数据库连接, 直连
    public static Connection connectionJWGL() throws SQLException {
        return DriverManager.getConnection(url_user,usename,password);
    }
    // 获取数据库连接, 池连
    public static Connection getConnection2() throws SQLException {
        return dataSource.getConnection();
    }
}

后端servler服务端编写

package com.westos.sql;

import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;
import sun.misc.Request;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @ClassName JdbcServer
 * @Author zhang-peng-zhan
 * @Date 2019/1/11 18:10
 */
@WebServlet(urlPatterns = "/myform")   //此处需要和JSP表单的action对应,因为需要从表单获取信息
public class JdbcServer extends HttpServlet {  //继承
    static String  username = null;
    static String  password = null;
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        username = req.getParameter("username");  //这个方法是通过表单里每个标签的name属性,获取到标签的值。
        password = req.getParameter("password");

        try( Connection connection = JDBCutils.getConnection2()) { //通过连接池获取数据库的连接
            try (PreparedStatement preparedStatement = connection.prepareStatement
                    ("insert into data(ID,username,password) values (null,?,?)")){//构造sql语句
                preparedStatement.setString(1,username);  //填入数据
                preparedStatement.setString(2,password);
                boolean execute = preparedStatement.execute(); //执行sql语句
                if (!execute){  //执行成功
                    System.out.println("添加成功");
                    req.getRequestDispatcher("/formsuccess.jsp").forward(req, resp); //调用req.getRequestDispatcher("/formsuccess.jsp").forward(req, resp)方法是跳转到一个新的JSP页面,告诉用户添加成功。
                }else {
                    System.out.println("添加失败");
                    req.getRequestDispatcher("/formfail.jsp").forward(req, resp); //同理
                }
            }
        }catch (MySQLIntegrityConstraintViolationException e){
            req.getRequestDispatcher("/formfail.jsp").forward(req, resp);  //捕捉异常,添加失败,继续跳转失败页面。
        }
        catch (SQLException e) {
            e.printStackTrace();
            req.getRequestDispatcher("/formfail.jsp").forward(req, resp);  //捕捉异常,添加失败,继续跳转失败页面。
        }
    }
}
  • 这样一个比较稍微综合的例子,可以方便理解servlet和JSP之间的如何搭配运作。
  • 至于servlet里的那些方法都可以参考JAVAAPI文档

浏览器获取后端数据

  • 上面例子主要是服务器从前端获取数据
  • 下面看看服务器如何传递数据,给浏览器。
  • 涉及知识点:作用域
    1. request对象下有一个方法
    2. request.setAttribute(“变量名”, 对象);
    3. 这个方法,可以将你需要的数据(对象,字符串,集合等等一系列)放到一个区域里,然后在JSP页面,可以使用一种EL表达式获取到你传递的数据。
      看看一个例子
servlet端
@WebServlet(urlPatterns = "/servletuser")
public class test2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        user zhangsan = new user("zhangsan", "123456"); //这里需要一个user对象的参数
        //设置属性jsp里面的对象名
        req.setAttribute("user",zhangsan);
        //跳转jsp页面
        req.getRequestDispatcher("uesr.jsp").forward(req,resp);
        System.out.println("test2跳转到user.jsp处理");
    }
}
JSP端

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <p>jsp接收到了!</p>
     ${user.toString()}  //这个就是EL表达式,获取到zhangsan对象的信息
     ${user.name}  //虽然是.name的调用但是实际上他调用的是get()方法,而不是name这个属性名。
</body>
</html>

  • request.setAttribute(“变量名”, 对象);
    • 在使用该方法时候,可以看见将zhangsan这个对象放进了一个作用域,并且给它在作用域里面起名为user;而且在jsp页面使用EL表达式取的是user,也就是zhangsan在作用域里的名称。而不是他自己对象的名字。
    • 还有一点强调,调用方式。EL表达式由${}组成
      • ${ 变量名 }
      • ${ 变量名.属性名 } el 表达式中的属性名,对应着java对象中的 get,set方法名
  • EL表达式
    • 取普通变量 ${ 变量名 }
    • 取对象变量 ${ 变量名.属性名 }
    • 取集合变量 因为需要遍历涉及到一个循环的标签。
1.需要添加依赖在maven项目的pom文件下
引入标签库 jar包
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
2.加载依赖完成后,在JSP页面生命使用的标签库。
<%@ taglib prefix="标签前缀" uri="标签的唯一标识" %>
位置添加在html标签最上面例如:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
。。。。
</html>
  • forEach 进行遍历
<c:forEach items="要遍历的集合" var="临时变量名" begin="起始的下标" end="结束下标" varStatus="保存下标的对象">
</c:forEach>
  • if 条件判断
<c:if test="条件">内容</c:if>
  • choose 条件判断
<c:choose>
    <c:when test="条件1">内容</c:when>
    <c:when test="条件2">内容</c:when>
    <c:when test="条件3">内容</c:when>
    <c:otherwise>内容</c:otherwise>
</c:choose>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <div id="div1">  //打印输出一个9*9乘法表
        <table border="1" >
            <c:forEach begin="1" end="9" var="i">
                <tr>
                <c:forEach begin="1" end="${i}" var="j">
                    <td>
                    ${i}*${j}=${i*j}
                    </td>
                </c:forEach>
                </tr>
            </c:forEach>
        </table>
    </div>
    <div id="div2">  //遍历一个map集合
        <c:forEach items="${use}" var="map">
            <p>${map.key}------${map.value}</p>
        </c:forEach> 
    </div>
    <div id="div3"> // 获取一个时间对象
        <p>${date}</p>
    </div>
    <div id="div4"> //获取对象的password属性值
        <p>
            ${param.password}
        </p>
    </div>
    <div id="div5">   //相当于switch语句
        <p>
            <c:choose >
                <c:when test="${password>100 and password<200 }">sb</c:when>
                <c:when test="${password>200 and password<400}">sa</c:when>
                <c:otherwise>sc</c:otherwise>
            </c:choose>
        </p>
        <hr>
        <p>
            <c:choose >
                <c:when test="${param.password>100 and param.password<200 }">sb</c:when>
                <c:when test="${param.password>200 and param.password<400}">sa</c:when>
                <c:otherwise>sc</c:otherwise>
            </c:choose>
        </p>
    </div>

</body>
</html>

Servlet的四个作用域

  • 前面说存取变量数据需要涉及一个作用域的知识,在servlet的程序里,作用域一共有四个,分别是(request域 session域 application域 page域),这四个作用域笼统的说都有传递参数数据的作用。但是应用的范围大小不一样。
  • 按大小范围来讲:page < request < sesssion < application
  • page作用域:作用的范围在一个页面,不可以从一个页面到另一个页面,当页面结束,page作用域的参数就被释放掉。
  • request作用域:可以跨越jsp和Servlet,实现数据传递,但是一刷新所有的值就需要重新计算。
  • session作用域:又称为一次会话,作用范围在浏览器范围之内,只要浏览器不关闭,session作用域对象一直存在,其实也可以手动设置存在时间。
  • application作用域:作用于整个服务器,只要tomcat不关闭,application会一直存在。可以手动删除。
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页