JavaWeb

JavaWeb就是在B/S模式下,使用Java开发综合性web服务网站的技术。

Tomcat

下载:tomcat官网https://tomcat.apache.org/

根据jdk和操作系统选择合适的版本

 

 使用

下载成功后无需安装,解压到某个盘下即可

解压后的目录

 

目录说明
bin保存tomcat中的可执行文件,如启动tomcat的startup.bat文件等
conf保存tomcat的配置文件,如server.xml文件可以修改默认的8080端口
lib保存tomcat运行时所需的jar文件
logs保存tomcat运行时产生的日志文件
temps保存tomcat运行时产生的临时文件
webapps保存发布在tomcat山歌应用程序
work保存tomcat运行时产生的编译文件

启动tomcat

打开bin目录下的start.bat文件,tomcat启动后的默认端口号为8080,。

在浏览器输入localhose:8080或127.0.0.0:8080,即可进入tomcat默认启动页面

该页面位于ROOT目录下,名为index.jsp,localhost:8080表示进入ROOT目录下访问index文件

Maven

用于管理项目的工具。如管理项目中所需的jar文件,打包项目等。通过在maven项目中加入某个jar文件所需的dependency(依赖),让其自动从Maven仓库中下载对应jar文件。

Maven依赖官网

地址https://mvnrepository.com/,在这个网站中查询所需的jar文件的依赖

 Maven本地仓库

Maven默认的配置文件会从官网下载jar文件,速度较慢,并且下载的jar文件保存在c盘。

这里在D盘的根目录下新建了一个MavenRepository的本地仓库,用于保存下载后的jar文件,

设置国内镜像下载

 配置文件

 使用

下载配置Maven – Welcome to Apache Maven

使用IDEA自带:在新建项目时选择Maven项目即可,在设置中更改IDEA自带的Maven配置。

 

 IDEA创建不同Maven项目

使用easyexcel实现读写excel文件

新建项目

 

 导入所需依赖

在Maven依赖官网搜索easyexcel

easyexcel使用文档EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel

然后选择版本 复制依赖,粘贴到项目的pom.xml文件下的dependencies标签中

普通Maven项目没有dependencies标签,需要自己编辑。

pom文件更新后,需要刷新Maven,让其自动下载所需依赖。

 编写实体类

属性上使用@ExcelProperty("列名")注解设置要读取的excel文件表头

/*
* 员工表对应实体类
* 这里省略
* get/set
* toString()
* 全参构造
* 无参构造
* */
public class Employee {
    @ExcelProperty("编号")
    private int id;
    @ExcelProperty("姓名")
    private String name;
    @ExcelProperty("性别")
    private String sex;
    @ExcelProperty("身份证")
    private String idcard;
    @ExcelProperty("部门")
    private String dept;
    @ExcelProperty("入职时间")
    private String joinDate;
    @ExcelProperty("电话")
    private String phone;
}

读excel

//要读取的文件,必须存在
File file = new File("C:\\Users\\Administrator\\Desktop\\员工信息.xlsx");

// EasyExcel.read(要读取的文件,要读取的实体类.class,PageReadListener对象,参数为一个lambda表达式).sheet().doRead();
//PageReadListener对象需要设置泛型为要读取的实体类型,lambda表达式参数为读取到的数据集合
EasyExcel.read(file, Employee.class, new PageReadListener<Employee>((emps) -> {
    for (Employee emp : emps) {
        System.out.println(emp);
    }
})).sheet().doRead();

写excel

//要写入的文件,可以不存在
File target = new File("d:\\employee.xlsx");

// EasyExcel.write(要写入的目标文件,要写入的实体类.class).sheet("表名").doWrite(要写入的数据集合)
EasyExcel.write(target, Employee.class).sheet("员工信息").doWrite(数据集合);

在IDEA中创建基于Maven的Web项目

1.新建webapp模板

 2.在src目录下新建文件夹,之后在此创建java文件

 3.修改项目中web.xml版本为4.0

打开project Structure 移除默认的2.3版本的web.xml文件,移除后点apply应用 重新添加web.xml文件,选择4.0版本

4.配置 tomcat服务器

 

 5.将项目部署到tomcat中

 

 并修改项目的访问路径:application context:xxxxxxx

 6.启动项目:

启动tomcat:默认启动web页中自带的index.jsp文件。

web资源目录结构

webapp下如果有index文件,访问项目后会自动访问index文件,如果没有名为index的文件,就会出现404,表示index页面不存在。

项目上下文路径

域名+端口+项目名:称为项目上下文路径

如localhost:8080/web就是项目的上下文路径,可以理解为项目根目录

webapp目录直接通过项目上下文路径访问,无需显示写出

更新了项目中的内容后,根据需要选择重启还是重新部署 

修改项目编译时的jdk版本

 解决控制台中文乱码

Edit Custom VM Options中添加:-Dfile.encoding=utf-8

重启IDEA

Servlet

Servlet表示Server+Applet,意味运行在服务器上的程序。是一个被动运行程序,每次请求都要执行。

BS结构客户端访问服务器端的流程

 编写Servlet的步骤

1.在项目中导入Servlet所需依赖

 粘贴在pom.xml文件中的dependencies标签下

2.在项目的java目录下,新建一个类,继承HttpServlet,重写doget和dopost方法

/*
 * 编写Servlet的步骤
 * 1.导入依赖
 * 2.创建一个类,继承HttpServlet,重写doGet和doPost方法
 * 3.在web.xml中设置访问该类的url映射
 * */
public class FirstServlet extends HttpServlet {
    //普通的控制台项目,需要主动运行main方法执行程序
    //web项目中的java程序,需要被动运行,在用户通过浏览器访问某个程序的url映射时执行

    /*
     * 当浏览器发送的是get类型的请求,执行这个方法
     * */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("get请求");
    }

    /*
     * 当浏览器发送的是post类型的请求,执行这个方法
     * */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("post请求");
    }
}

3.在web.xml文件下,配置Servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!--xml是一个配置文件,属于一种标记语言,通过标签定义内容-->
    <!--声明Servlet-->
    <servlet>
        <!--servlet命名-->
        <servlet-name>firstServlet</servlet-name>
        <!--servlet类的全限定名(路径+文件名)-->
        <servlet-class>FirstServlet</servlet-class>
    </servlet>
    <!--定义Servlet的请求映射-->
    <servlet-mapping>
        <!--要映射的servlet名,与上方定义的servlet-name一致-->
        <servlet-name>firstServlet</servlet-name>
        <!--请求映射url,必须以/开头-->
        <!--之后通过项目上下文路径+该路径,就能访问FirstServlet类-->
        <url-pattern>/first</url-pattern>
    </servlet-mapping>
</web-app>

复制资源的相对路径

启动tomcat,访问"localhost:8080/项目路径/first"即可访问自定义servlet类中的doget方法

三层架构

 在软件开发中,并不是将所有的功能集成到一个类中或文件中实现,而是要将其分层处理,从而达到高内聚,低耦合的目的

低耦合是指降低各个模块之间的关联程度,便于开发和维护,各个模块各司其职。高内聚指各个模块的功能不开再分。

  • 数据访问层:用于连接操作数据库的类,对数据进行增删改查
  • 业务逻辑层:用于处理业务逻辑,在适当的情况下访问数据访问层中的内容
  • 视图表现层:用于展示和提供用户输入的渠道,在适当的情况下访问业务逻辑层中的内容

访问服务器某个URL的方式

在浏览器的地址栏输入对应的URL,属于get请求

使用a标签,在href中定义对应的URL,属于get请求

使用form表单,在action中定义对应的URL,根据method属性的值控制get或post请求

页面向服务器端提交数据的方式

  • 使用form表单的name属性提交

 提交的数据会暴露在浏览器的地址栏中

  • 使用form表单中的name属性隐式提交

在原form基础上加上method="post"

提交的数据不会暴露在浏览器的地址栏中

  • 通过"?参数1=值&参数2=值"的方式显示提交

在浏览器地址栏中输入:http://localhost:8080/web01/getOne?id=23

  • 使用a标签
<a href="http://localhost:8080/web01/login?username=admin&password=123123">登录</a>

服务器端获取前端提交的数据

前端页面传递数据

<a href="URL?id=123">访问</a>
<form action="URL">
<input name="id">
<input type="submit">
</form>

在servlet的doget或dopost方法中

通过request.getParameter("name值或?后的参数")获取数据,返回值为String

 解决请求和响应时的中文乱码

HTTP状态码

常见状态码说明
200成功
404要访问的资源不存在
500服务器内部错误
405方法不允许

 表单提交数据注意

表单如果是get方式提交,无法在action中使用?提交数据

表单如果是post提交,可以再action中使用?提交数据

 使用表单的隐藏域提交,无论get还是post方式,都能提交数据

 使用Servlet实现表单的增删改查

 实体类,数据访问类dao层,业务逻辑类:service最后是servlet

首页

 添加页

 

 web.xml文件中常用标签

web.xml是web模块的配置文件

<?xml version="1.0" encoding="UTF-8"?>

 

 

 配置过滤器,一个特殊的servlet

 

 Servlet的生命周期

构造一次-->init()一次-->service()-->destory()一次

在第一次访问某个servlet时,执行:1.构造方法一次,2.init()方法一次;3.有Service()方法执行service()方法,没有则执行doxxx方法,如果都没有,报405状态码,表示请求不允许;4.当服务器停止时,执行destory()方法一次。

使用注解开发Serclet

 

 JSP

java Server Pages:使用java开发,运行在服务器上的页面,称为jsp,jsp页面的后缀名为.jsp

jsp实际是一个java类,具体为一个Servlet,第一次访问某个jsp页面,相当于编译运行servlet

访问jsp的流程:编译对应的Servlet-->运行servlet

使用jsp时,可以导入该依赖,在jsp中方便提示

 

 JSP的组成

1.HTML元素*

2.Java脚本*

<%

java代码

%>

3.表达式*

用于在页面中输出变量或字符串。无需分号

4.注释:jsp注释在访问jsp时不会再浏览器中看见,html注释在访问jsp时会在浏览器中看见

5.指令:<% 指令名 属性="值"%>

  • page指令

用于设置当前页面的属性

  • include指令

用于嵌入其他页面

  • taglib指令

用于导入其他标签库

6.声明:可以在这里定义方法,全局变量等

<%!
void fun(){}
%>

7.动作:使用标签定义一些功能

<jsp:单词></jsp:单词>
//包含另一张页面
<jsp:include page="路径"></jsp:include>

路径问题

绝对路径:

完整路径

相对路径:

/:从项目根目录出发。即域名+端口号

./:从当前位置出发

../退出当前目录后出发

 跳转

HTML to HTML/JSP

<a href="另一个页面的路径">跳转</a>

<form action="另一个页面的路径">
    <input type="submit">
</form>

HTML to Servlet

<a href="某个servlet的URL映射">跳转</a>
<form action="某个servlet的URL映射">
    <input type="submit">
</form>

 Servlet/JSP to Servlet/JSP/HTML

请求转发

request.getRequestDispatcher("目的路径").forward(request,response)

使用请求转发跳转到目的地后,浏览器的地址栏是最初访问的路径

可以再请求转发时,在request对象中保存数据,如request.getParameter(),request.setAttribute()

在执行查询时,通常将查询后的结果保存在request对象中,使用请求转发跳转到页面中

 请求转发,用户只发送一次请求,得到一次响应。在request中保存的数据会一直存在。浏览器的地址栏中显示的是最初访问的路径,而不是最终的目标路径。用于地址栏中的路径不会改变,所以刷新页面就表示访问对应的内容。所以在对数据的增删改后,不要使用请求转发,否则会重复提交,执行查询时建议使用请求转发

重定向

response.sendRedirect("目的路径")

使用重定向跳转到目的地后,浏览器的地址栏是最终访问的目的地路径

如果在重定向时使用request对象保存数据,后续无法获取保存的内容

在执行增删改后使用重定向跳转到目的地,防止重复提交。

 重定向用户不止发送了一个请求,在第一次的请求中保存的数据,一旦中途有重定向,后续无法获取该数据

跳转到目的地后,浏览器地址栏会变成最终的地址。在执行增删改后,使用重定向防止重复提交。

跳转过程中传递参数

由页面发送数据到servlet或jsp,通常使用表单元素或在某个URL后使用"?参数=值"方式提交参数,获取时使用request.getParameter("参数")获取

<a href="xxxx?id=11">删除</a>
<form action="xxxx" >
    <input type="hidden" name="id" value="11">
</form>
//返回值为String
String str=request.getParameter("id");

由servlet发送数据到页面,使用request.setAttributr(String str,Object obj)保存obj到请求对象中,命名为str,获取时使用request.getAttribute(String str)

 

<%
//返回值为Object类型
objcet obj=request.getAttribute("obj");
List list=(list)obj;
%>

分页和条件分页

核心SQL语句

 dao

/*
     * 条件分页查询
     * 根据图书名的关键字分页查询
     * */
public List<BookInfo> queryPageByCondition(int page, int size, String keyword) {
    List<BookInfo> list = new ArrayList<>();
    String sql = "select * from book_info where book_name like concat('%',?,'%') limit ?,?";
    conn = DBHelper.getConn();
    try {
        pst = conn.prepareStatement(sql);
        pst.setString(1, keyword);
        pst.setInt(2, (page - 1) * size);
        pst.setInt(3, size);
        rs = pst.executeQuery();
        while (rs.next()) {
            int bookId = rs.getInt(1);
            int typeId = rs.getInt(2);
            int bookPrice = rs.getInt(5);
            int bookNum = rs.getInt(8);
            String bookName = rs.getString(3);
            String bookAuthor = rs.getString(4);
            String publisher = rs.getString(6);
            String publishDate = rs.getString(7);
            String bookImg = rs.getString(9);
            BookInfo bookInfo = new BookInfo(bookId, typeId, bookName, bookAuthor, bookPrice, publisher, publishDate, bookNum, bookImg);
            list.add(bookInfo);
        }
    } catch (SQLException e) {
        System.out.println("查询所有异常" + e);
    } finally {
        DBHelper.release(conn, pst, rs);
    }
    return list;
}

servlet

@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    String op = req.getParameter("op");
    if (op == null) {
        return;
    }
    switch (op) {
        case "queryByPage":
            //获取关键字
            String keyword = req.getParameter("keyword");

            //获取总记录数
            double sumCount = bookInfoService.getSumCount(keyword);
            //根据总数和size计算最大页
            int maxPage = (int) Math.ceil(sumCount / 8);
            //将最大页保存到请求中
            req.setAttribute("maxPage", maxPage);

            //获取当前页
            String page = req.getParameter("page");

            //访问该servlet,调用后续的查询,得到查询的集合
            List<BookInfo> books = bookInfoService.queryPageByCondition(Integer.parseInt(page), 8,keyword);
            //将查询出的集合保存在请求中,命名为list    req.setAttribute(String str,Object obj);
            req.setAttribute("list", books);
            //跳转到jsp页面中,这里只能使用请求转发
            req.getRequestDispatcher("pages/bookshop_index.jsp").forward(req, resp);
            //resp.sendRedirect("pages/bookshop_index.jsp");
            break;
    }
}

页面

<%@ page import="com.hqyj.book_shop.entity.BookInfo" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style>
            //样式略
        </style>
    </head>
    <body>
        <%
        //获取当前的关键字
        String keyword = request.getParameter("keyword");
        %>
        <div class="tool">
            <form action="http://localhost:8080/book_shop/book">
                <input type="hidden" name="op" value="queryByPage">
                <input type="hidden" name="page" value="1">
                <input type="text" name="keyword" value="<%=keyword%>" placeholder="请输入书名关键字">
                <input type="submit" value="搜索">
            </form>
        </div>
        <div class="main">
            <div class="left"></div>
            <div class="right">
                <%--获取servlet中保存的数据--%>
                <%
                int maxPage = (Integer) request.getAttribute("maxPage");
                List<BookInfo> list = (List) request.getAttribute("list");
                for (BookInfo book : list) {
                    %>
                <div>
                    <a href="http://localhost:8080/book_shop/book?op=findById&id=<%=book.getBookId()%>">
                        <img src="/book_shop/pages/imgs/<%=book.getBookImg()%>">
                    </a>
                    <p class="info"><%=book.getBookAuthor()%>:《<%=book.getBookName()%>》</p>
                    <p><span class="price">¥<%=book.getBookPrice()%></span><span
                                                                                 class="oldPrice">¥<%=book.getBookPrice()%></span></p>
                </div>
                <%}%>
            </div>
        </div>
        <div class="pageTool">
            <%
            /*获取当前页*/
            int curPage = Integer.parseInt(request.getParameter("page"));
            /*下一页*/
            int nextPage = curPage == maxPage ? maxPage : curPage + 1;
            /*上一页*/
            int prevPage = curPage == 1 ? 1 : curPage - 1;
            %>
            <a href="http://localhost:8080/book_shop/book?op=queryByPage&keyword=<%=keyword%>&page=1">首页</a>
            <a href="http://localhost:8080/book_shop/book?op=queryByPage&keyword=<%=keyword%>&page=<%=prevPage%>">上一页</a>
            <a>共<%=maxPage%>页/第<%=curPage%>页</a>
            <a href="http://localhost:8080/book_shop/book?op=queryByPage&keyword=<%=keyword%>&page=<%=nextPage%>">下一页</a>
            <a href="http://localhost:8080/book_shop/book?op=queryByPage&keyword=<%=keyword%>&page=<%=maxPage%>">尾页</a>
        </div>
    </body>
</html>

四大作用域对象

作用域:共享数据的区域:

如request就是一个作用域对象,request.setAttributr(String str,Object obj)在请求作用域中保存数据。

request.getAttribute(String str)在请求作用域中获取数据。

pageContext

当前页对象,共享数据的范围为当前页面 如果不在一个页面,数据无法读取。

request:

请求对象,共享数据的范围为一次请求。只要请求不改变(不重定向)数据一直保存在请求对象中。

session

会话对象,共享数据的范围为指定的会话时长。  默认会话超时为30min 表示如果30分钟没有对该站点进行访问,自动销毁会话。

application;

应用程序(项目)对象。  共享数据的范围为整个项目中

作用域范围

由大到小:application>session>request>pageContext

以上的作用域对象,都有这几个方法。

作用域对象的使用:

在jsp页面中使用

在jsp中,作用域对象为内置对象,可以直接通过单词使用:

p1.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%--在JSP中,作用域对象属于内置对象,无需定义,可以直接使用--%>
<%--向四个作用域中保存数据--%>
<%
    pageContext.setAttribute("str","保存在pageContext中的字符串");
    request.setAttribute("str","保存在request中的字符串");
    session.setAttribute("str","保存在session中的字符串");
    application.setAttribute("str","保存在application中的字符串");
%>
<%--当前页中获取数据的情况--%>
<h1><%=pageContext.getAttribute("str")%></h1>
<h1><%=request.getAttribute("str")%></h1>
<h1><%=session.getAttribute("str")%></h1>
<h1><%=application.getAttribute("str")%></h1>
<%--使用a标签跳转,相当于重定向--%>
<%--session和application中的数据可以获取--%>
<a href="p2.jsp">跳转到p2</a>
<%
    //销毁session后,无法读取session中保存的数据
    //session.invalidate();
    //移除某作用域对象中的数据
    application.removeAttribute("str");
    //使用请求转发跳转,除pageContext之外的作用域中保存的数据都可以获取
    request.getRequestDispatcher("p2.jsp").forward(request,response);
%>
</body>
</html>

p2.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>pageContext:<%=pageContext.getAttribute("str")%></h1>
<h1>request:<%=request.getAttribute("str")%></h1>
<h1>session:<%=session.getAttribute("str")%></h1>
<h1>application:<%=application.getAttribute("str")%></h1>
<hr>
<h1>来自于servlet中保存在session里的数据:<%=session.getAttribute("msg")%></h1>
</body>
</html>

在servlet中使用:

pageContext:servlet中不会使用pageContext,它本身就是一个类,定义成员变量即可

request:使用doGet()/doPost()/service()等方法的HttpServletRequest参数即可

protected void service(HttpServletRequest req, HttpServletResponse resp){
    //req即是request对象  
}

session:

protected void service(HttpServletRequest req, HttpServletResponse resp){
    //通过req对象调用getSession()方法获取session对象
    HttpSession session = req.getSession();
}

application

protected void service(HttpServletRequest req, HttpServletResponse resp){
    //通过getServletContext()方法获取application对象
    ServletContext application = getServletContext();
}

总结:

  • pageContext对象用于jsp页面中,保存的数据只能在当前页面中使用。
  • request对象常用于servlet中保存查询后的集合。使用请求转发跳转到jsp页面中输出集合
  • session对象常用于登录后保存登录的用户,在其他页面中共享用户对象
  • application对象保存共享于整个项目中的数据。

Ajax

Ajax=Asynchronous JavaScript and XML(异步的JavaScript 和XML)

AJAX最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容

任何的浏览器都支持ajax,通过原生的js使用ajax不方便,这里使用jquery封装后的ajax

使用

1.在页面引入jquery文件

<script src="jquery文件路径"></script>

2.给某个节点绑定事件后使用ajax提交数据

<script>
	$("#btn").click(()=>{
        $.ajax({
            //访问的地址
            url:'URL地址',
            //提交的数据,以键值对的形式提交,也可以提交单个数据
            data:{
                id:123,
                op:"xxx"
            },
            //提交方式
            type:"post",
            //访问成功后的回调函数
            succuss:(res)=>{//res为访问URL地址后的返回值          
            },
            //访问失败后的回调函数
            error:(res)=>{}
        });
    });
</script>

登录

dao层:

public Customer findByPhoneAndPwd(String phone, String password) {
    String sql = "select * from customer where phone=? and password=?";
    conn = DBHelper.getConn();
    try {
        pst = conn.prepareStatement(sql);
        pst.setString(1, phone);
        pst.setString(2, password);
        rs = pst.executeQuery();
        while (rs.next()) {
            int id = rs.getInt(1);
            String nickName = rs.getString(4);
            String trueName = rs.getString(5);
            String address = rs.getString(6);
            return new Customer(id, phone, password, nickName, trueName, address);
        }
    } catch (SQLException e) {
        System.out.println("登录异常" + e);
    } finally {
        DBHelper.release(conn, pst, rs);
    }
    return null;
}

service层

public Customer login(String phone, String password) {
    return customerDao.findByPhoneAndPwd(phone, password);
}

servlet层:

case "login":
                String phone = req.getParameter("phone");;
                String password = req.getParameter("password");
                Customer login = customerService.login(phone, password);

                if (login != null) {
                    //登录成功后,创建购物车对象,保存到session中
                    Cart cart = new Cart();
                    session.setAttribute("cart", cart);
                    //将登录的用户保存在session中
                    session.setAttribute("customer", login);
                    //跳转到查询首页数据的servlet
                    resp.sendRedirect("http://localhost:8080/book_shop/book?op=queryByPage&page=1&keyword=");
                } else {
                    //错误时,给前端反馈的字符串
                    resp.getWriter().print("error");
                }
                break;

页面ajax部分

$("#sub").bind("click",()=>{
        $.ajax({
            url:"http://localhost:8080/book_shop/customer",//提交的路径
            data:{//提交的数据data:{k:v,k:v}   data:xxx
                op:"login",
                phone:$(".inp[name=phone]").val(),
                password:$(".inp[name=password]").val()
            },
            type:"post",//提交方式
            success:(res)=>{
                if(res=="error"){
                    alert("用户名或密码错误")
                }else{
                    location.href="http://localhost:8080/book_shop/book?op=queryByPage&page=1&keyword=";
                }
            }
        });
    })

注册

dao层:

/*
     * 检测电话是否存在
     * */
    public int phoneExists(String phone) {
        //查询该电话出现的次数
        String sql = "select count(id) from customer where phone=?";
        conn = DBHelper.getConn();
        try {
            pst = conn.prepareStatement(sql);
            pst.setString(1, phone);
            rs = pst.executeQuery();
            //返回查询到的结果
            if (rs.next()) {
                return rs.getInt(1);
            }
        } catch (SQLException e) {
            System.out.println("检测电话是否存在" + e);
        } finally {
            DBHelper.release(conn, pst, rs);
        }
        return 0;
    }
    /*真正添加*/
    public int insert(Customer customer) {
        String sql = "insert into customer values(null,?,?,?,?,?)";
        conn = DBHelper.getConn();
        try {
            pst = conn.prepareStatement(sql);
            pst.setString(1, customer.getPhone());
            pst.setString(2, customer.getPassword());
            pst.setString(3, customer.getNickName());
            pst.setString(4, customer.getTrueName());
            pst.setString(5, customer.getAddress());
            return pst.executeUpdate();
        } catch (SQLException e) {
            System.out.println("注册异常" + e);
        } finally {
            DBHelper.release(conn, pst, rs);
        }
        return 0;
    }

service层:

/*
     * 注册业务流程
     * 根据电话查询是否存在,不存在则添加,存在返回false
     * */
    public boolean register(String phone, String password) {
        //检测电话是否存在
        if (customerDao.phoneExists(phone) == 1) {
            return false;
        }
        //真实注册
        Customer customer = new Customer();
        customer.setPhone(phone);
        customer.setPassword(password);
        customer.setNickName("用户" + phone.substring(7));
        return customerDao.insert(customer) > 0;
    }

servlet层:

case "register":
                //注册,注册的电话号码不能重复
                String regPhone = req.getParameter("phone");;
                String resPwd = req.getParameter("password");
                //调用注册
                if (customerService.register(regPhone, resPwd)) {
                    resp.getWriter().print("注册成功");
                } else {
                    resp.getWriter().print("该手机号码已注册");
                }
            case "checkphone":
                String checkphone=req.getParameter("phone");
                resp.getWriter().print(customerService.phoneExists(checkphone));
                break;

页面js部分:

<script>
    /*电话文本框内容改变事件*/
    $("input[name=phone]").change(function () {
        $.ajax({
            url: "http://localhost:8080/book_shop/customer",
            data: {
                op: "checkPhone",
                phone: $(this).val()
            },
            type: "post",
            success: (res) => {
                if (res == "true") {
                    //显示提示文字
                    $("#warning").show();
                    //禁用按钮,修改按钮文件
                    $("#sub").attr("disabled","true");
                    $("#sub").val("请重新输入手机号码");
                } else {
                    //隐藏提示文字,恢复按钮功能
                    $("#warning").hide();
                    $("#sub").removeAttr("disabled");
                    $("#sub").val("注册");
                }
            }
        });
    });
    /*表单提交事件*/
     document.forms[0].onsubmit = () => {
         var phone = document.querySelector(".inp[name=phone]").value;
         var password = document.querySelector(".inp[name=password]").value;
         //1开头的11位数字
         var regexPhone = /^1\d{10}$/;
         //非空格的至少6位密码
         var regexPwd = /^[^\s]{6,}$/;
         if (!regexPhone.test(phone)) {
             alert("电话格式有误");
             return false;
         }
         if (!regexPwd.test(password)) {
             alert("密码中不能出现空格且至少6位");
             return false;
         }
     }
</script>

登出

servlet:

case "logout":
                //销毁session
                session.invalidate();
                //跳转登录页
                resp.sendRedirect("/book_shop/pages/login.html");
                break;

EL

Expression Language 表达式语言:是为了时jsp中输出写起来更加简便,替换jsp中的<%=%>,即表达式

主要输出保存在某个作用域中的数据

特点

  • 减少代码(获取对象,转换对象,获取对象属性)

如果通过"某个作用域对象.setAttribute(String str,Object obj)"方法保存的对象。在jsp页面中,如果用表达式,写为<%=str>;如果使用EL,写为${str}.会依次从pageContext-->request-->session-->application中获取指定对象,如果一旦从某个作用域中获取到了对象,就不再判断后续作用域。也可以指定从某个作用域中获取对象,如${session.str}表示从session作用域中获取对象

  • 免去非空判断

如果要使用的某个对象不存在,不会输出null,而是输出空字符串""

使用

1.获取保存在作用域中的对象

  • 获取保存在某个作用域中的对象:${对象名}
  • 从指定的作用域中获取对象
作用域单词对应作用域代码
pageScope当前页pageContext${pageScope.对象}
requestScope请求request${requestScope.对象}
sessionScope会话session${sessionScope.对象}
applicationScope项目application${applicationScope.对象}
  • 输出对象的属性

${对象名.属性名}

${对象名["属性名"]}

要保证该属性有对应的get方法

  • 输出对象的方法返回值

${对象名.方法名()}

举例

//在servlet中,将一个集合保存在请求对象request中
//Person有name、sex和age属性
Person p1 = new Person("a","男",20);
Person p2 = new Person("b","男",20);
Person p3 = new Person("c","女",20);
List list = new ArrayList();
list.add(p1);
list.add(p2);
list.add(p3);
req.setAttribute("list",list);

使用请求转发跳转到页面中:

<!--传统JSP中的表达式-->
<%
List list = (List)request.getAttribute("list");
//需要获取、转换后才能遍历使用
%>
<table>
    <%
    for(Object obj in 集合){
        %>
    <td><%=obj.get属性()%></td>
    <%}%>
</table>
<!--使用EL和JSTL后-->
<table>
    <c:forEach items="${list}" var="p">
        <!--使用EL-->
        <td>${p.name}</td>>
        <td>${p.sex}</td>>
        <td>${p.age}</td>>
    </c:forEach>
</table>

2.用户获取当前项目上下文路径(根目录+项目名)

http://localhost:8080/book_shop是一个项目上下文路径。

在JSP中使用${pageContext.request.contetxPath}获取项目上下文路径

<form action="${pageContext.request.contextPath}/book?op=xxx"></form>
<a href="${pageContext.request.contextPath}/book?op=xxx"></a>
<img src="${pageContext.request.contextPath}/pages/imgs/xxx.jpg">
<script>
	$.ajax({
        url:"${pageContext.request.contextPath}/book?op=xxx"
    });
</script>

3.在页面中获取请求中携带的参数

可以使用EL获取表单提交或地址中?后传递的数据,使用${param.参数}表示request.getParameter("参数")方法获取的数据

 在xxx.jsp中:

${param.username}获取提交的数据

注意

  • web.xml版本在4.0之后,在jsp中使用EL时,默认可以识别。
  • 如果JSP中无法识别EL,原样输出${}符号时,在指令(<%@%>中加入isELignored="false"表示不忽略EL)

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%>

  • 如果在使用EL的过程中,出现PropertyNotFoundException异常,表示未发现指定属性原因:1.缺少指定属性,2.指定属性没有对应的get方法。

JSTL

java Server Page Standarded Tag Library JSP标准标签库:可以使用JSTL中特定标签,来替换JSP中常见的java代码,如循环判断等。减少JSP中java代码,提高页面的可读性。

使用:

导入jstl依赖

 在jsp页面中,加入标签库指令

<!--在当前页面中使用jstl,以c为标签前缀-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

这句话可以在使用循环时自动生成

具体使用:1.定义变量或给变量赋值

<c:set var="变量名" value="值"></c:set>
<c:set var="name" value="admin"></c:set>

2.if判断

<c:if test="判断条件">
	满足时执行
</c:if>
session.setAttribute("user",用户对象);
<c:if test="${empty user}">
	<span>请登录</span>
</c:if>
<c:if test="${!empty user}">
	<span>${user.username}</span>
</c:if>

3.遍历list集合

//如在servlet中,将查询到的集合保存在request对象中
request.setAttribute("list",查询到的集合)
<table>
    <!--<c:forEach items="要遍历的集合" var="遍历出的每个对象">-->
    <c:forEach items="${list}" var="obj"> 
        <tr>
            <td>${obj.属性}</td>
        </tr>
    </c:foreach>
</table>

4.遍历Map集合

<%
    HashMap<String,String> hm = new HashMap();
    hm.put("yyds","永远单身");
    hm.put("awsl","阿伟死了");
    hm.put("u1s1","有一说一");
    application.setAttribute("hm",hm);
%>
<c:forEach items="${hm}" var="kv">
    <%--${键值对.key} 获取键   ${键值对.value} 获取值   --%>
    <h2>${kv.key}--${kv.value}</h2>
</c:forEach>

使用JSTL和EL输出购物车中的信息

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="com.hqyj.book_shop.util.Cart" %>
<%@ page import="com.hqyj.book_shop.entity.BookInfo" %>
<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Title</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            body {
                background-color: #f5f5f5;
            }
            .main {
                width: 1240px;
                height: 628px;
                margin: 20px auto 20px;
                background-color: #fff;
            }
            table {
                float: left;
                width: 600px;
                margin-top: 50px;
                margin-left: 320px;
                border-collapse: collapse;
            }
            th, td {
                width: 120px;
                height: 20px;
                border: 1px solid skyblue;
            }
        </style>
    </head>
    <body>
        <jsp:include page="top.jsp"></jsp:include>
        <div class="main">
            <table>
                <tr>
                    <th>图书编号</th>
                    <th>图书名称</th>
                    <th>图书单价</th>
                    <th>购买数量</th>
                    <th>小计</th>
                    <th>操作</th>
                </tr>
                <c:if test="${empty cart.getCart()}">
                    <tr>
                        <td colspan="6">当前购物车中无商品</td>
                    </tr>
                </c:if>
                <c:if test="${!empty cart.getCart()}">
                    <%--定义变量表示总合--%>
                    <c:set var="sumPrice" value="0"></c:set>
                    <c:forEach items="${cart.getCart()}" var="kv">
                        <tr>
                            <td>${kv.key.bookId}</td>
                            <td>${kv.key.bookName}</td>
                            <td>${kv.key.bookPrice}</td>
                            <td>${kv.value}</td>
                            <%--el中可以使用算术运算--%>
                            <td>${kv.key.bookPrice*kv.value}</td>
                            <td>
                                <a href="${pageContext.request.contextPath}book?op=remove&bookId=${kv.key.bookId}">移除</a>
                            </td>
                            <%--每次循环将小计累加到总价中--%>
                            <c:set var="sumPrice" value="${sumPrice + kv.key.bookPrice * kv.value}"></c:set>
                        </tr>
                    </c:forEach>
                    <tr>
                        <td colspan="4">总计</td>
                        <td>${sumPrice}</td>
                        <td><a href="${pageContext.request.contextPath}/book?op=clear">清空购物车</a></td>
                    </tr>
                </c:if>
            </table>
        </div>
    </body>
</html>

带有外键关联的表的查询

表结构:主表book_type,从表book_info

实体类:

 

 数据访问层:

方式一:定义连接查询的sql语句,适合关联字段比较少的情况

Dao层:

public class BookInfoDao{
    private Connection conn;
    private PreparedStatement pst;
    private ResultSet rs;
    /*
    	查询从表数据
    */
    public List<BookInfo> queryAll() {
        List<BookInfo> list = new ArrayList<>();
        //定制连接查询的sql
        String sql = "select bi.*,type_name from book_info bi,book_type bt where bi.type_id=bt.type_id";
        conn = DBHelper.getConn();
        try {
            pst = conn.prepareStatement(sql);
            rs = pst.executeQuery();
            while (rs.next()) {
                /*
                	1-9是bi.*表示从表中的数据
                */
                int bookId = rs.getInt(1);
                int typeId = rs.getInt(2);
                int bookPrice = rs.getInt(5);
                int bookNum = rs.getInt(8);
                String bookName = rs.getString(3);
                String bookAuthor = rs.getString(4);
                String publisher = rs.getString(6);
                String publishDate = rs.getString(7);
                String bookImg = rs.getString(9);
                //10是额外的主表中的数据type_name
                String typeName= rs.getString(10);
                //创建从表对象,不包含外键属性
                BookInfo bookInfo = new BookInfo(bookId, typeId, bookName, bookAuthor, bookPrice, publisher, publishDate, bookNum, bookImg);
                //给外键属性赋值
                bookInfo.setBt(new BookType(typeId,typeName));
                list.add(bookInfo);
            }
        } catch (SQLException e) {
            System.out.println("查询所有异常" + e);
        } finally {
            DBHelper.release(conn, pst, rs);
        }
        return list;
    }
}

方式二:分别编写不同表的查询,使用子查询。

两个Dao层:

public class BookTypeDao{
    private Connection conn;
    private PreparedStatement pst;
    private ResultSet rs;
    /*
    	根据类型编号查询类型对象
    */
    public BookType findByTypeId(int typeId){
        String sql = "select * from book_type where type_id=?";
        conn = DBHelper.getConn();
        try {
            pst = conn.prepareStatement(sql);
            pst.setInt(1,typeId);
            rs = pst.executeQuery();
            while (rs.next()) {
                //返回查询到的图书类型对象
                return     new BookType(rs.getInt(1),rs.getString(2));
            }catch (SQLException e) {
                System.out.println("根据类型编号查询类型异常" + e);
            } finally {
                DBHelper.release(conn, pst, rs);
            }
            return null;
        }
    }
}


public class BookInfoDao{
    private Connection conn;
    private PreparedStatement pst;
    private ResultSet rs;
    //子查询时,需要用到另一个dao类中的方法
    private BookTypeDao bookTypeDao = new BookTypeDao();
    /*
    	查询从表数据
    */
    public List<BookInfo> queryAll() {
        List<BookInfo> list = new ArrayList<>();
        //定制连接查询的sql
        String sql = "select * from book_info";
        conn = DBHelper.getConn();
        try {
            pst = conn.prepareStatement(sql);
            rs = pst.executeQuery();
            while (rs.next()) {
                /*
                	1-9是bi.*表示从表中的数据
                */
                int bookId = rs.getInt(1);
                int typeId = rs.getInt(2);
                int bookPrice = rs.getInt(5);
                int bookNum = rs.getInt(8);
                String bookName = rs.getString(3);
                String bookAuthor = rs.getString(4);
                String publisher = rs.getString(6);
                String publishDate = rs.getString(7);
                String bookImg = rs.getString(9);
                //调用根据类型编号查询类型对象的方法
                BookType bt= bookTypeDao.findByTypeId(typeId);
				//创建从表实体对象
                BookInfo bookInfo = new BookInfo(bookId, typeId, bookName, bookAuthor, bookPrice, publisher, publishDate, bookNum, bookImg);
                //给外键属性赋值
                bookInfo.setBt(bt);
                list.add(bookInfo);
            }
        } catch (SQLException e) {
            System.out.println("查询所有异常" + e);
        } finally {
            DBHelper.release(conn, pst, rs);
        }
        return list;
    }
}

JSP内置对象

在jsp中,可以不用定义,就能直接使用的对象,称为内置对象。一共有9个内置对象

  • pageContext:作用域对象,当前页面作用域
  • request:作用域对象,请求作用域
  • session:作用域对象,会话作用域
  • application:作用域对象,项目作用域
  • response:响应对象
  • out:输出对象,相当于Servlet中的response.getWriter()方法的返回值对象。
  • page:表示页面自身对象,相当于servlet中的this
  • config:配置对象,获取servlet的配置信息。
  • exception:异常对象,只能使用在有isErrorPage="true"声明的jsp页面中,用于获取异常对象

Session和Cookie

session:称为会话,是一个作用域,使用session.setAttribute()保存数据,使用session.getAttribute()获取数据

默认session会话有效期为30分钟,可以更改,超时或关闭浏览器,session失效。保存在session中的数据,可以在同一个站点下的不同页面中共享。

session共享数据的原理

访问任意JSP页面时,默认都会创建一个JSESSIONID(可以取消自动创建),是一段session编号,保存在一个cookie文件中

 自动生成的cookie文件信息,可以看出,随着浏览器关闭,session到期

再次访问该页面时,会查询JSESSIONID是否存在,如果存在,直接使用,如果不存在,重新创建新的JSESSIONID

保存该JSESSIONID的cookie文件,有效期为浏览会话结束。所以关闭浏览器,session失效

session对象常用方法:

 设置项目全局session有效时长

在web.xml中设置,单位为min

cookie:

cookie是一个用于保存数据的对象,实际是一个保存在客户本地的文件。关闭浏览器,cookie依然存在。手动清理或自动超时清理后,数据随之消失。

cookie通常用于更久地保存数据,即便关闭浏览器,也能一直存在。如登录信息、购物车信息等

cookie中保存的数据有上限(4kb),

cookie在浏览器中保存的数量也有上限(30~300根据浏览器不同略有变化)。

创建cookie

 保存cookie:response.addCookie(ck);

遍历cookie:

session和cookie的对比:

  •  session中保存的数据可以是任意类型,没有大小限制;cookie中保存的是键值对,单个值大小上限为4kb

  • session中保存的数据存在服务器中,cookie中保存的数据存在浏览器中

  • session到期或随着浏览器关闭而失效,cookie如果设置了有效时长,即使关闭了浏览器也会存在,到期或手动清理时失效

过滤器Filter

是一个特殊的servlet:

 黑色线条表示在没有过滤器时的访问流程,红色线条表示在有过滤器后的访问流程,过滤器可以将指定的请求进行拦截,拦截后进行判断绝对是否放行执行后续的请求。通常用于权限控制或解决中文乱码。

使用:

1.新建一个类,继承HttpFilter

2.重写doFilter()方法,设置过滤条件

/*
 * 自定义过滤器
 * 1.创建一个类,继承HttpFilter
 * 2.重写受保护的doFilter方法
 * 3.配置过滤器
 * */
public class MyFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        //获取当前访问的uri(地址)
        String uri = req.getRequestURI();
        System.out.println(uri + "访问过滤器");
        //如果登录成功后,session会保存customer。
        //过滤器中判断当前session中是否存在customer
        if (req.getSession().getAttribute("customer") != null) {
            chain.doFilter(req, res);
            return;
        }
        //如果session中没有customer,只能放行登录、注册页及其相关静态资源和customer模块
        if (uri.contains("html")  || uri.contains("jquery")|| uri.contains("customer")) {
            chain.doFilter(req, res);
        }else{
            //否则跳转登录页
            res.sendRedirect("http://localhost:8080/book_shop/pages/login.html");
        }
    }
}

3.配置过滤器,过滤一切请求:

<!--声明一个过滤器-->
<filter>
    <!--过滤器名,无限制-->
    <filter-name>myFilter</filter-name>
    <!--过滤器类全限定名-->
    <filter-class>com.hqyj.book_shop.filter.MyFilter</filter-class>
</filter>
<!--配置过滤器映射-->
<filter-mapping>
    <!--过滤器名,与上方对应-->
    <filter-name>myFilter</filter-name>
    <!--过滤一切请求-->
    <url-pattern>/*</url-pattern>
</filter-mapping>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值