JavaWeb
使用Java开发Web服务的技术,统称为JavaWeb。
B/S与C/S模式
- B/S:Browser/Server 浏览器/服务器模式
- 用户只需要一个浏览器即可访问服务器
用户通过浏览器发送请求,访问服务器上的某个部署的项目,经过该项目的MVC,得到响应。
框架部分会使用SpringMVC替换现有的Servlet实现MVC的流程。
- C/S:Clint/Server 客户端/服务器模式
- 用户需要下载客户端才能访问服务器
Tomcat
提到Javaweb开发,必须得有Tomcat服务器。它是由Apache、Sun和其他公司及个人共同开发的web服务器。
免费、开源、轻量级,在中小型系统中普遍被使用。
是开发和调试Web项目的首选。
三层架构
在软件开发中,并不是将所有功能都交给一个类去实现,而是要将其进行分层,从而达到"高内聚、低耦合"的目的。
低耦合是指降低各个模块之间的关联程度,这样便于开发和维护,每个模块各司其职。
高内聚是指每个模块内的功能不可再分。
这样便于发现问题解决问题,不影响其他模块。
通常所说的三层架构中的三层,是指“数据访问层、业务逻辑层和视图表现层”
- 数据访问层,用于连接数据库,对数据做增删改查的操作
- 业务逻辑层,用于处理业务逻辑,在适当的情况下调用数据访问层中的方法
- 视图表现层,用于展示数据和提供用户输入数据的渠道,在适当的情况下调用业务逻辑层中的方法
Web项目开发模式
Model1
JSP+JavaBean模式。
JSP负责渲染数据和处理页面。
JavaBean是一个满足以下条件的类
- 被public修饰
- 其中的属性进行封装
- 用private修饰属性
- 提供get/set方法
- 有无参数的构造方法
这种模式,不适合复杂项目的开发。
jsp既要显示内容,又要处理数据,后期维护扩展不方便。
Model2(MVC)
MVC模式:模型-视图-控制器模式。
M:Model模型 用于封装数据处理数据,对应业务逻辑类、数据访问类、实体类
V:View视图 用于渲染数据,对应页面(jsp或html)
C:Controller控制器 用户调度用户请求,对应servlet
这种模式适合复杂项目的开发。
每个模块各司其职,耦合性低。
对于后期维护和扩展较为方便。
页面向服务端提交数据的方式
-
使用form表单的name属性显示提交
<form action="http://localhost:8080/day1/hero" method="get"> <input type="text" name="username"> <input type="submit"> </form>
提交的数据会暴露在浏览器的地址栏中
-
使用form表单的name属性隐式提交
<form action="http://localhost:8080/day1/hero" method="post"> <input type="text" name="username"> <input type="submit"> </form>
提交的数据不会暴露在浏览器的地址栏中
-
通过"?参数名=值"方式提交
-
在地址栏中输入URL的时候,末尾加入这部分
https://www.baidu.com/s?wd=hello
-
在a标签的href属性中加入这部分,如果有多个参数,通过&拼接
<a href="https://www.baidu.com/s?wd=hello&a=1&b=2">访问</a>
-
服务器端获取页面传递的数据
以上任何方式提交到服务器的数据,都可以使用以下方式获取。
String str=request.getParameter("name名或?后的参数名");
class TestServlet extends HttpServlet{
doGet(HttpServletRequest req,HttpServletResponse resp){
//获取表单提交的数据req.getParameter("表单中某个表单元素的name值");
String username = req.getParameter("username");
}
doPost(HttpServletRequest req,HttpServletResponse resp){
doGet();
}
}
表单提交数据注意事项
-
表单通过action提交设置的路径,如果要在路径中传递参数,只能使用post方式提交
<form action="xxxxx?参数=值" method="post"> </form>
-
使用get方式提交,无法识别action路径中的参数,如果要传递参数,使用隐藏域
<form action="xxxxx" method="get"> <input type="hidden" name="参数名" value="参数值"> </form>
路径
-
/
表示根目录,即域名:端口号,如localhost:8080
-
./
表示当前目录,如在localhost:8080/Web03/page.html页面中访问./index.html,相当于localhost:8080/Web03/index.html
-
…/
表示向上一层目录,如在localhost:8080/Web03/page.html页面中访问…/index.html,相当于localhost:8080/index.html
使用EL的${pageContext.request.contextPath}表示当前项目的上下文路径,
如localhost:8080/Web03/pages/index.html中使用${pageContext.request.contextPath}/hello.html,
相当于localhost:8080/Web03/hello.html
Servlet的生命周期
构造方法**–>init()–>service()/doGet()/doPost()–>**destory()
在访问某servlet时
1.执行构造方法一次
2.初始化一次,调用init()方法
3.调用service()方法,之后每次访问都会调用该方法。有该方法时,doGet和doPost失效。
如果没有该方法,会根据请求方式试图调用doGet或doPost,如果没有相应的方法,会出现405状态码,表示请求方式不允许
4.在当前servlet所在项目从tomcat中停止时,销毁一次,调用destory()方法
使用注解开发Servlet
/*
* 使用注解开发Servlet
* 注解:@特定单词 如@Override
*
* 定义且配置Servlet的注解:@WebServlet("/请求映射")
* */
@WebServlet("/sysAdmin")
public class SysAdminServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) {
//访问该Servlet时要执行的内容
}
}
//@WebServlet("/sysAdmin")相当于在web.xml中进行配置servlet映射
web.xml中的相关配置
-
servlet
<!-- 声明servlet --> <servlet> <servlet-name>自定义servlet名</servlet-name> <servlet-class>servlet全限定名</servlet-class> <!-- servlet初始化参数 --> <init-param> <param-name>参数名</param-name> <param-value>参数值</param-value> </init-param> </servlet> <!-- 配置servlet请求映射 --> <servlet-mapping> <servlet-name>自定义servlet名</servlet-name> <url-patten>/映射名</url-patten> </servlet-mapping>
-
filter
<!-- 声明filter --> <filter> <filter-name>自定义filter名</filter-name> <filter-class>filter全限定名</filter-class> </filter> <!-- 配置filter请求映射 --> <filter-mapping> <filter-name>自定义filter名</filter-name> <!--过滤器通常用于解决中文乱码,要过滤所有请求--> <url-patten>/*</url-patten> </filter-mapping>
-
listener
<listener> <listener-class>监听器的全限定名</listener-class> </listener>
-
session
<!--设置全局session配置--> <session-config> <session-timeout>session有效时长,单位为分钟</session-timeout> </session-config>
-
全局参数
<!--设置全局参数--> <context-param> <param-name>参数名</param-name> <param-value>参数值</param-value> </context-param>
数据访问层(Dao)
现在使用JDBC实现查询,框架部分会使用MyBatis、MyBatisPlus或JPA,简化该层的写法。
跳转
请求转发forward
保存在request中的数据会一直存在
request.getRequestDispatcher("目的路径").forward(request,response);
重定向redirect
保存在request中的数据会丢失(不是同一个请求)
response.sendRedirect("目的路径");
跳转时传递数据
保存
作用域对象.setAttribute(String str,Object obj);
//将一个名为str的对象obj保存到某个作用域中。request就是一个作用域。
List<泛型> 集合 = dao.查询();
//将查询到的集合保存到请求中,命名为list
request.setAttribute("list",集合);
获取
Object obj = 作用域对象.getAttribute(String str);
//获取到的数据是Object类型,通常需要转型
List<泛型> list =(List<泛型>) request.getAttribute("list");
JSP
Java Server Page
使用Java开发、运行在服务器上的页面。
jsp文件的后缀名为".jsp"。
由于最初由servlet渲染页面,在Java代码中加入大量html的内容,使用极不方便。所以Sun公司推出了JSP,可以在页面中加入java代码,让页面成为动态页面。
JSP页面的本质是一个java文件(servlet)。
在访问某个jsp页面时,会让该页面重新编译为.java文件–>.class文件,所以第一次访问某个JSP页面时会慢一些。
四大作用域对象
作用域:共享数据的区域
pageContext
当前页面对象。共享数据区域范围为当前页面。
如果不在同一个页面,数据无法读取。
request
请求对象。共享数据区域范围为一次请求。
如果跳转中途使用了重定向,数据无法读取。
session
会话对象。会话是用户访问服务器时的某个时间段。
共享数据区域范围在这个时间段内,默认30分钟。
如果在指定时间内没有操作或销毁会话时,数据无法读取。
application
项目对象。共享数据区域范围为整个项目。
作用域范围
application > session > request > pageContext
以上四个作用域对象,都有这几个方法
//将某个对象obj保存到作用域中,命名为str
作用域对象.setAttribute(String str,Object obj);
//从某个作用域中获取保存的某个对象
Object obj = 作用域对象.getAttribute(String str);
//从某个作用域中移除某个保存的对象
作用域对象.removeAttribute(String str);
作用域对象的使用
在JSP页面中
作用域对象也称为内置对象,直接通过对应的单词使用
p1.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
//在jsp中使用pageContext页面上下文对象,跳转到p2时不能使用
pageContext.setAttribute("str","保存在pageContext作用域中的字符串");
//在jsp中使用request请求对象,请求转发到p2时可以使用,重定向到p2时不能使用
request.setAttribute("str","保存在request中的字符串");
//在jsp中使用session会话对象,在默认的30分钟内,没有销毁,哪种跳转都能在p2中使用
session.setAttribute("str","保存在session中的字符串");
//在jsp中使用application应用程序对象,整个项目中任何页面都能使用
application.setAttribute("str","保存在application中的字符串");
//以上四个作用域对象,也是jsp中的内置对象,无需定义
//销毁会话
//session.invalidate();
//使用请求转发跳转到p2.jsp
//request.getRequestDispatcher("p2.jsp").forward(request,response);
//使用重定向跳转到p2.jsp
response.sendRedirect("p2.jsp");
%>
<h1><%=pageContext.getAttribute("str")%></h1>
</body>
</html>
p2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3><%=pageContext.getAttribute("str")%></h3>
<h3><%=request.getAttribute("str")%></h3>
<h3><%=session.getAttribute("str")%></h3>
<h3><%=application.getAttribute("str")%></h3>
</body>
</html>
在servlet中使用
-
pageContext
servlet本身就是一个java类,在类中定义成员变量,就能在当前类中使用。
所以在servlet中不会使用pageContext对象
-
request
使用doGet/doPost/service方法中的HttpServletRequest参数req
-
session
//在servlet中使用session,需要通过请求对象request调用getSession()方法 HttpSession session= req.getSession();
-
application
//通过getServletContext()方法获取的ServletContext类型对象,就是当前项目对象 ServletContext application = getServletContext();
总结
- 在jsp页面中使用pageContext保存的数据,只能共享于当前页面
- 通常在servlet中查询后的数据保存在request中,使用请求转发跳转到其他页面,在对应的页面中数据数据
- 通常在登录后,将登录的用户保存在session中,无论用哪种方式跳转,都能从session中获取当时登录的用户。
- 在application中保存一些共享于整个项目中的数据
EL
Expression Language 表达式语言
是为了使JSP写起来更加简便,替换JSP中的<%=%>,简化了JSP页面中输出数据的操作。
主要输出保存在某个作用域中的数据。
特点
如果通过"某个作用域对象.setAttribute(“cus”,customer)"方法保存的对象,
在JSP页面中如果用表达式,使用<%=cus%>,如果用EL,使用**${cus}**输出。
会依次从pageContext–>reqeust–>session–>application中获取指定对象,
如果一旦从某个作用域中获取到了指定对象,就不再判断后续作用域。
也可以输出指定作用域中的对象。
-
只能输出保存在作用域中的对象
-
减少代码(省去了获取对象、转换的过程)
-
免去非空判断
- 如果某个要输出的对象不存在,不会输出null,而是输出空字符串""。
使用
在页面中输出保存在作用域中的对象
-
从作用域中依次查询并输出对象
${对象名}
-
从指定作用域中输出对象
作用域 对应作用域 代码 pageScope 当前页pageContex ${pageScope.对象} requestScope 请求request ${requestScope.对象} sessionScope 会话session ${sessionScope.对象} applicationScope 项目application ${applicationScope.对象} -
输出对象的属性
${对象名.属性名} ${对象名["属性名"]}
-
输出对象的方法返回值
${对象名.方法名()}
如在servlet中
Person p = new Person("admin","男",20);
request.setAttribute("p",p);
跳转到某个页面中
<html>
<head></head>
<body>
<%-- 如果不用EL,先获取对象,向下转型 --%>
<% Person p =(Person) request.getAttribute("p");%>
<%-- 如果p为null,会报错,如果name没有赋值,会输出null --%>
<h3>
<%=p.getName()%>;
</h3>
<%--如果使用EL,无需获取对象,无需转型,直接通过保存的对象名.属性名即可--%>
<h3>
${p.name}
</h3>
<%--使用EL输出对象的属性时,该对象必须要有getXX()方法--%>
<%--如果没有在任何作用域中获取到对象p,或对象p没有name属性,不会保存,输出空字符串--%>
<h3>
${p["name"]}
</h3>
</body>
</html>
在页面中获取请求中的参数
用于获取表单提交的数据或超链接?后传递的数据。
使用${param.参数名}替换request.getParameter(“参数”)。
如有表单或超链接
<form action="page.jsp">
<input type="text" name="username">
<input type="submit">
</form>
<a href="page.jsp?username=admin">跳转</a>
在page.jsp中获取
<html>
<head></head>
<body>
<%-- 传统写法--%>
<% String username = request.getParameter("username");%>
<h3>
<%=username%>;
</h3>
<%--如果使用EL--%>
<h3>
${param.username}
</h3>
</body>
</html>
用于获取当前项目上下文(根目录+项目名)路径
如http://localhost:8080/Web03/就是一个项目上下文路径,
在JSP中使用**${pageContext.request.contextPath}**获取项目上下文路径
<form action="${pageContext.request.contextPath}/servlet映射">
</form>
<a href="${pageContext.request.contextPath}/页面路径">超链接</a>
注意
-
web.xml版本在4.0之后,在JSP中使用EL时,默认可以识别。
-
如果JSP无法识别EL,在指令(<%@ %>)中加入 isELIgnored="false"表示不忽略EL。
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false"%>
-
如果在使用EL过程中,出现PropertyNotFoundException异常,表示未发现指定属性,原因有
- 缺少指定属性
- 指定属性没有对应的get方法
JSTL
Java Server Page Standarded Tag Library JSP标准标签库
可以使用JSTL中的特定标签,来替换JSP中常见的Java代码。如循环判断等,减少Java代码,提高页面的可读性。
使用
1.导入JSTL对应的依赖
https://mvnrepository.com/artifact/javax.servlet/jstl/1.2
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
2.在JSP页面中,加入标签库指令
<%--在当前页面中使用jstl,加入以下指令--%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
这句话可以不写,在使用循环遍历时会自动生成。
3.具体用法
-
定义变量或给变量赋值
<c:set var="变量名" value="值"></c:set>
如
<c:set var="num" value="123123"></c:set>
-
if判断
<c:if test="判断条件"> 满足条件时的内容 </c:if>
如在servlet中
request.setAttribute("person",new Person("ez","男"));
在Jsp中
<c:if test="${person.sex=='男'}"> <input type="raido" name="sex" checked>男 <input type="raido" name="sex" >女 </c:if>
-
遍历List集合
<c:forEach items="要遍历的集合" var="遍历出的对象名"></c:forEach>
如servlet中保存了集合
List<BookInfo> list = dao.queryAll(); request.setAttribute("list",list);
在jsp页面中
<%--判断集合为空--%> <c:if test="${empty list}"> 无数据 </c:if> <c:forEach items="${list}" var="bi"> <tr> <td>${bi.bookName}</td> <td>${bi.bookAuthor}</td> </tr> </c:forEach>
-
遍历Map集合
<c:forEach items="要遍历的集合名" var="遍历出的键值对的名称"> ${键值对名.key.属性} ${键值对名.value.属性} </c:forEach>
如
<% HashMap<String,String> hm=new HashMap(); hm.put("yyds","永远单身"); hm.put("xswl","吓死我了"); hm.put("pyq","朋友圈"); session.setAttribute("hm",hm); %> <c:forEach items="${hm}" var="kv"> <!--遍历键--> <h3>${kv.key}</h3> <!--遍历值--> <h3>${kv.value}</h3> </c:forEach>
Ajax(异步)
Asynchronous Javascript And XML
异步JavaScript和XML
一种数据交互方式,请求和响应是异步的。
使用ajax能实现在整个页面不重新加载的情况下,更新局部内容。
使用
浏览器都是支持异步提交,原生的JavaScript就能实现ajax,但使用极不方便,所以都是使用jquery封装后的** . a j a x ( ) ∗ ∗ 或 .ajax()**或 .ajax()∗∗或.get() $.post()等函数。
1.在页面中导入jquery文件
<!--使用Ajax,需要导入jquery--> <script src="jquery文件路径"></script>
2.在script标签中写ajax
<script> 某个节点.事件(function(){ //使用ajax异步提交数据 $.ajax({ //访问的URL地址 url:"servlet映射或具体url", //提交的数据 data:{ //键:值 "形参":值, "形参":值 }, //提交方式 type:"get/post/put/delete", //成功访问URL后的回调函数 success:function(res){//res表示访问URL后返回的数据 }, //访问URL失败时的回调函数 error:function(){ } }); }); </script>
具体案例
servlet
package com.hqyj.bookShop.servlet; import com.hqyj.bookShop.dao.CustomerDao; import com.hqyj.bookShop.entity.Customer; import com.hqyj.bookShop.util.Cart; 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 javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/customer") public class CustomerServlet extends HttpServlet { CustomerDao dao = new CustomerDao(); @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); String op = req.getParameter("op"); switch (op) { case "login": //获取登录信息 String phone = req.getParameter("phone"); String password = req.getParameter("password"); //调用登录 Customer login = dao.login(phone, password); if (login != null) { //将登录成功的对象,保存到session中 session.setAttribute("customer", login); //使用输出流对象输出一个字符串"ok" resp.getWriter().print("ok"); } else { //使用输出流对象输出一个字符串"ok" resp.getWriter().print("error"); } break; } } }
页面
<html> <head></head> <body> <input type="text" name="phone" placeholder="请输入手机号"/><br><br> <input type="password" name="password" placeholder="请输入密码"/><br><br> <input id="submit" type="button" value="登录"/> </body> <script src="./../system/bootstrap-3.4.1-dist/js/jquery-3.6.2.min.js"></script> <script> //如果是普通按钮,需要写单击事件 $("#submit").click(function () { //获取输入的信息 let phone = $("input[name=phone]").val(); let password = $("input[name=password]").val(); if (phone == "" || password == "") { alert("输入不能为空"); return; } //使用ajax提交登录信息 $.ajax({ //请求地址 url: "http://localhost:8080/Web03/customer", //提交方式 type: "post", //提交数据 data: { "op":"login", "phone": phone, "password": password }, //访问成功(能正常访问指定地址)后的回调函数。 success: function (res) { if(res=="error"){ alert("用户名或密码错误"); } if(res=="ok") { location.href="http://localhost:8080/Web03/bookInfo?op=search"; } } }); }); //如果是表单,需要写表单提交事件 // $("form:eq(0)").submit(); </script> </html>
JSP内置对象
在jsp页面中有一些对象是已经定义好了可以直接使用的,称为内置对象。
一共有9个内置对象。
“rrppsoace”
- request
- 请求作用域对象
- response
- 响应对象
- pageContext
- 当前页作用域对象
- session
- 会话作用域对象
- page
- 当前jsp页面对象
- out
- 输出对象
- application
- 项目作用域对象
- config
- 配置对象
- exception
- 异常对象
Session
通常用session保存登录时的用户信息,实现在各个页面中共享信息或防止未登录的情况下访问。
使用session时,会创建一个JSESSIONID,保存在cookie中,在浏览器开启状态下,该JSESSIONID默认会有30分钟的有效期,
},
//访问成功(能正常访问指定地址)后的回调函数。
success: function (res) {
if(res==“error”){
alert(“用户名或密码错误”);
}
if(res==“ok”) {
location.href=“http://localhost:8080/Web03/bookInfo?op=search”;
}
}
});
});
//如果是表单,需要写表单提交事件
// $(“form:eq(0)”).submit();
JSP内置对象
在jsp页面中有一些对象是已经定义好了可以直接使用的,称为内置对象。
一共有9个内置对象。
“rrppsoace”
- request
- 请求作用域对象
- response
- 响应对象
- pageContext
- 当前页作用域对象
- session
- 会话作用域对象
- page
- 当前jsp页面对象
- out
- 输出对象
- application
- 项目作用域对象
- config
- 配置对象
- exception
- 异常对象
Session
通常用session保存登录时的用户信息,实现在各个页面中共享信息或防止未登录的情况下访问。
使用session时,会创建一个JSESSIONID,保存在cookie中,在浏览器开启状态下,该JSESSIONID默认会有30分钟的有效期,
如果在30分钟内没有对session进行操作或关闭浏览器,该cookie就会销毁,对应的session就会失效。