一、环境搭建
1、JSP介绍
什么是jsp?
JSP全称Java server page 直译就是"运行在服务端的页面"。
我们可以直接在JSP文件里写HTML代码,使用上把它当作HTML文件。而且JSP中的HTML/CSS/JS等的写法和HTML文件中的写法是一摸一样的。我们还可以把Java代码内嵌在JSP页面中,很方便地把动态数据渲染成静态页面
JSP = HTML + Java
2、开发工具介绍
开发Java的工具一般常见的为Eclipse、MyEclipse、Idea
Eclipse与MyEclipse的区别
Eclipse是一个IDE(Integrated Developing Environment),而这个IDE是允许安装第三方开发的插件来使自身的功能得到扩展和增强的,而MyEclipse就是其中的一种有名的插件集之一,主要是J2EE开发,MyEclipse将开发者常用到的一些有用的插件都集合起来,提供一种高级编程环境,但它是收费的。
MyEclipse是Eclipse的插件版,同时MyEclipse要钱,Eclipse免费使用
下载链接:
https://www.eclipse.org/downloads/packages/
web版
MyEclipse会自带JDk,可以直接使用
Eclipse使用必须安装JDK
JDk 是Java语言的软件开发工具包,主要用于移动设备、嵌入式设备上的Java应用程序。JDK是整个Java开发的核心,它包含了JAVA的运行环境(JVM + Java系统类库)和java工具。
JDK下载链接(选择自己需要的版本下载即可):
https://www.oracle.com/cn/java/technologies/downloads/
JDK的配置
1、测试:按下win + R ,输入cmd,然后回车输入java -version
出现这个说明配置成功 ,如果没有则需要手动配置:
WIN + X Y
系统信息 高级信息设置 环境变量
1、新建系统变量 JAVA_HOME 值:JDK安装路径
2、选中"path"点击"编辑"选项 新建填入 %JAVA_HOME%\bin %与JAVA_HOME%\jre\bin
3、新建系统变量CLASSPATH
值:.;%Java_Home%\bin;%Java_Home%\lib\dt.jar;%Java_Home%\lib\tools.jar
最后重复上面的测试步骤即可
3、服务器安装与配置
tomcat下载链接:(常见的版本8、8.5、9,新版本不稳定,可能会闪退)
启动tomcat只需要打开
tomcat目录结构
1、bin目录主要是用来存放tomcat的命令,主要有两大类,一类是以.sh结尾的(linux命令),另一类 是以.bat结尾的(windows命令)。
2、conf目录主要是用来存放tomcat的一些配置文件。 server.xml可以设置端口号、设置域名或IP、默认加载的项目、请求编码。
3、lib目录主要用来存放tomcat运行需要加载的jar包。
4、logs目录用来存放tomcat在运行过程中产生的日志文件
5、temp目录用户存放tomcat在运行过程中产生的临时文件。
6、webapps目录用来存放应用程序,当tomcat启动时会去加载webapps目录下的应用程序。可以以文件 夹、war包、jar包的形式发布应用。
7、work目录用来存放tomcat在运行时的编译后文件,例如JSP编译后的文件。
通过访问localhost:8080查看tomcat是否打开服务
手动部署项目:将项目复制到webapps目录下即可
二、servlet&表单提交&页面跳转
1、servlet
1.1、什么是servlet?
Servlet是在服务器端运行的Java程序,可以接收客户端的请求并作出响应
Servlet可以动态生成HTML内容对客户端进行响应
Servlet与jsp的关系
1.2、实现接口,初识代码
public class HelloServlet implements Servlet {
public LoginServlet1() {创建}
public void destroy() {销毁}
public ServletConfig getServletConfig() {
return null;
}
public String getServletInfo() {
return null;
}
public void init(ServletConfig arg0) {初始化}
public void service(ServletRequest arg0, ServletResponse arg1) {处理请求}
}
1.3、学会配置和映射
<!-- 配置servlet(HelloServlet) -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.zking.HelloServlet</servlet-class>
</servlet>
<!-- 映射servlet(HelloServlet) -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/请求路径</url-pattern>
</servlet-mapping>
<!-- 注意:但凡是改了web.xml文件的内容 务必记得重启服务器再运行!!! -->
1.4、掌握servlet的生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
- Servlet 初始化后调用 init () 方法。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 销毁前调用 destroy() 方法。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
1.5、获取servlet初始化参数和上下文参数
1.5.1、初识代码(推荐使用)
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp){
处理get请求
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
处理post请求
}
}
1.5.2、初始化参数
<!-- 配置servlet(HelloServlet) -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.zking.HelloServlet</servlet-class>
<!-- 初始化参数 -->
<init-param>
<param-name>参数名</param-name>
<param-value>参数对应值</param-value>
</init-param>
</servlet>
<!--只能在对应的一个servlet中拿到值:-->
this.getInitParameter("参数名");
1.5.3、上下文参数
<context-param>
<param-name>参数名</param-name>
<param-value>参数对应值</param-value>
</context-param>
<!--可被整个应用共享:-->
this.getServletContext().getInitParameter("参数名");
1.6、servlet应用:处理用户登录请求
1.6.1、为简化配置,推荐采用注解方式
@WebServlet("/请求url")
public class LoginServlet extends HttpServlet {}
//其等同于
<!-- 配置servlet(LoginServlet) -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.zking.LoginServlet</servlet-class>
</servlet>
<!-- 映射servlet(LoginServlet) -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/请求url</url-pattern>
</servlet-mapping>
1.6.2、HttpServletRequest方法(请求)
【String getParameter(String name)】:根据name值得到value值
【String[ ] getParameterValues(String name)】:根据name值得到多个value值 例如:爱好
【void setCharacterEncoding(String charset)】:设置请求的编码方式 防止中文乱码
【void setAttribute(String key, Object value)】:存值[键值对的方式]
【Object getAttribute(String key)】:根据键拿到值
1.6.3、HttpServletResponse方法(响应)
【void setContentType(String arg0)】:设置响应的编码方式
【PrintWriter getWriter()】:获得内置对象out
2、表单提交方式
<form action="请求路径url" method="get/post"></form>
表单提交有两种方式:
1.get(默认) 地址栏会显示信息,安全性低;有数据长度的限制
2.post 反之 以后推荐使用post
3、页面跳转方式
1、重定向
resp.sendRedirect("xx.jsp");
out.print("<script>alert('提示信息');location.href='页面地址';</script>");
2、转发
req.getRequestDispatcher("xx.jsp").forward(req, resp);
3、区别
重定向: 地址栏发生改变;不可携带数据跳转;可跳转到任意资源;在客户端发挥作用
转发: 地址栏不发生改变,停留在了之前请求的位置;可以携带数据跳转;只可转发到当前项目内资源;在服务端发挥作用
三、域对象&EL表达式&JSTL
1、jsp内置对象之域对象
1.1、什么是jsp的内置对象?
JSP的内置对象是指在JSP页面系统中已经默认内置的Java对象,这些对象不需要开发人员显式声明即可使用。一共有9个:
分别为request、response、session、application、out、pageContext、config、page和exception。
1.2、什么是域对象?
可以用于存储数据的内置对象,它们作用范围不同。一共有4个:
分别为request、session、application、pageContext。
1.3、域对象怎么存值和拿值?
域对象.setAttribute(String key,Object value)
域对象.getAttribute(String key)
1.4、域对象作用范围的区别?
1. pageContext: 可以存储数据,作用范围是当前页面有效。
2. request: 可以存储数据,作用范围是同一个请求,转发有效。
3. session: 可以存储数据, 作用范围是同一个会话有效,常用于保存用户登录信息。
4. application: 可以存储数据,作用范围是同一个应用。
1.5、常用内置对象与servlet的对应关系
/*
* request :HttpServletRequest 【req】
* response :HttpServletResponse【resp】
* session :HttpSession(通过req.getSession())
* out :PrintWriter(通过resp.getWriter())
* application :ServletContext(this.getServletContext())
*/
1.6、jsp标签中转发用法
<jsp:forward page="goods.do"></jsp:forward>
2、EL表达式
2.1、什么是EL表达式?
EL即 Expression Language(表达式语言)
2.2、为什么要用EL表达式?
1、为了替代jsp页面中的复杂代码
2、EL表达式不会在页面显示null
2.3、EL的语法
${EL expression}
${obj.name}
【注意:${obj.name}实质是调用obj的getName()方法】
【注意:sname必须是stu实体类中的属性名!!!】
eg:${stu.sname}实质就是调用了stu.getSname()方法
eg:${aa}实质就是拿域对象中键为aa的值
2.4、EL中的隐含对象(作用域)
pageScope、requestScope、sessionScope、applicationScope 在键出现冲突(重复)的时候
2.5、EL运算符
//算术、关系、逻辑运算符同java一致
eg:${2>1&&5!=6}
//empty/not empty运算符 判断是否为空/不为空
eg:${empty ls}
3、JSTL
3.1、什么是JSTL?
JSTL(JavaServerPages Standard Tag Library)JSP标准标签库,惯称c标签。
3.2、为什么要用JSTL?
使用了EL表达式可以简化JSP页面代码,但是如果需要进行逻辑判断、循环遍历怎么办?
3.3、JSTL核心标签库组成
JSP标准标签库(JSTL)是一个JSP标签集合,它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务,比如迭代,条件判断,XML文档操作,国际化标签,SQL标签。 除了这些,它还提供了一个框架来使用集成JSTL的自定义标签。
根据JSTL标签所提供的功能,可以将其分为5个类别。
- 核心标签
- 格式化标签
- SQL 标签
- XML 标签
- JSTL 函数
3.4、使用步骤
下载jstl-1.2.jar
网址:https://mvnrepository.com/artifact/javax.servlet/jstl/1.2
下载standard-1.1.2.jar
网址:https://mvnrepository.com/artifact/taglibs/standard/1.1.2
1、将两个JSTL的jar包放到WebContent->WEB-INF->lib下
2、在所需的JSP页面添加taglib指令
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
3.5、语法
3.5.1、通用标签:set remove out
set标签用于给变量设置值和作用范围:<c:set var="变量名" value="值" scope="作用域"></c:set>
out标签在页面上显示信息或变量值: <c:out value=""></c:out>
remove标签用于删除作用域内的变量:<c:remove var="变量" scope="作用域"/>
3.5.2、条件标签;if
<c:if test="条件">
</c:if>
3.5.3、迭代标签:forEach forTokens
<!--1、forEach用于循环遍历-->
<c:forEach items="要遍历的集合对象" var="变量" varStatus="状态" begin="开始" end="结束" step="增量">
循环体代码…
</forEach>
<!--2、forTokens用于分割-->
<c:forTokens items="要分割的内容" delims="用什么分割" var="变量">
</c:forTokens>
<!--常用代码:-->
<c:forEach items="${ls}" var="g">
商品名称:${g.gname}
商品价格:${g.gprice}
</c:forEach>
四、增删改查功能实现
登录逻辑流程图
1、增加
触发器+序列实现自增
--序列
create sequence seq_goods;
--触发器:前触发
create or replace trigger t_goods
before insert
on tb_goods
for each row
begin
:new.gid := seq_goods.nextval;--插入之前给商品编号列赋值
end;
增加逻辑流程图
取表的最大序列+1
/**
* 拿到id(标识列)
* @param tabName 表名
* @param colName 列名
* @return id
*/
public int getID(String tabName,String colName) {
int n=0;
try {
con=DBHelper.getCon();
String sql="select nvl(max("+colName+"),0) from "+tabName;
ps=con.prepareStatement(sql);
rs=ps.executeQuery();
if(rs.next()) {
n=rs.getInt(1)+1;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBHelper.close(con, ps, rs);
}
return n;
}
//运用
int gid = getID("tb_goods", "gid");
g.setGid(gid);
2、删除
删除逻辑流程图
删除方法
public int del(int id){
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = DBHelper.getCon();
String sql = "delete from bs_book where id = ?";
ps = con.prepareStatement(sql);
ps.setInt(1, id);
return ps.executeUpdate();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return 0;
}
del.do代码
package com.zking.servlet;
import java.io.IOException;
import java.util.List;
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 com.zking.biz.IBookBiz;
import com.zking.biz.impl.BookBizImpl;
import com.zking.dao.impl.BookDaoImpl;
import com.zking.dao.impl.UserDaoImpl;
import com.zking.entity.Book;
import com.zking.entity.User;
@WebServlet("/del.do")
public class DeleteServlet extends HttpServlet{
private IBookBiz bd = new BookBizImpl();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
//前往首页,并且展示数据
String id = req.getParameter("id");
bd.del(Integer.valueOf(id));
resp.sendRedirect("home.do");
}
}
前端实现
<table class="table table-hover">
<tr class="danger">
<td>编号</td>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>操作</td>
</tr>
<c:forEach items="${ books }" var="s">
<tr>
<td>${ s.id }</td>
<td>${ s.title }</td>
<td>${ s.price }</td>
<td>${ s.author }</td>
<td><a href="del.do?id=${ s.id }">删除</a>|<a href="aa.do?id=${ s.id }">修改</a></td>
</tr>
</c:forEach>
</table>
3、修改
修改思路
1、修改前业务处理(selvlet:preupddate.do)
//实例化dao
GoodsDao gd=new GoodsDao();
//接收gid
String gid = req.getParameter("gid");
//根据gid拿到商品对象=单个查询
Goods goods = gd.getGoods(gid);
//存起来
req.setAttribute("goods", goods);
//转发
req.getRequestDispatcher("update.jsp").forward(req, resp);
2、前端页面处理(update.jsp)
页面显示编号,但不可编辑
商品编号:<input type="text" value="${goods.gid}" name="gid" readonly>
商品名称:<input type="text" value="${goods.gname}" name="gname">
页面不显示编号 隐藏域传值
隐藏域(会随着表单的提交而提交)传值 必须写在表单中
<input type="hidden" name="gid" value="${goods.gid}">
3、修改后业务处理(servlet:update.do)
//实例化dao
GoodsDao gd=new GoodsDao();
//设置编码方式
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//接收表单提交的数据
String gid = req.getParameter("gid");
String gname = req.getParameter("gname");
String s = req.getParameter("gprice");
String ginfo = req.getParameter("ginfo");
double gprice=Double.parseDouble(s);
//实例化商品对象
Goods g=new Goods(gname, gprice, ginfo);
//调用dao方法 连接数据库进行判断
int n = gd.update(g, gid);
if(n>0){//修改成功
//重定向跳转去加载并展示数据
resp.sendRedirect("goods.do");
}
4、查询
查询逻辑
模糊查询后端功能代码
/**
* 模糊查询的方法
* @key 模糊查询关键字
* @title 模糊查询的列名
* @return 返回List集合
*/
public List<Book> queryAll(String key,String title){
//判断关键字是否为空,为空则改为空字符串
if(key==null) {
key = "";
}
//判断如果列名为空则对标题进行模糊查
if(title==null){
title ="title";
}
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
List<Book> books = new ArrayList<>();
try {
con = DBHelper.getCon();
String sql = "select * from bs_book where "+title+" like ? order by id";
ps = con.prepareStatement(sql);
ps.setString(1, "%"+key+"%");
rs = ps.executeQuery();
while(rs.next()) {
Book book = new Book();
book.setId(rs.getInt(1));
book.setTitle(rs.getString(2));
book.setPrice(rs.getDouble(3));
book.setAuthor(rs.getString(4));
books.add(book);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return books;
}
selvlet代码(home.do)
req.setCharacterEncoding("utf-8");
//前往首页,并且展示数据
String key = req.getParameter("key");
String type = req.getParameter("type");
List<Book> list = bd.queryAll(key,type);
req.setAttribute("key", key);
req.setAttribute("type", type);
req.setAttribute("books", list);
req.getRequestDispatcher("home.jsp").forward(req, resp);
前端展示代码
<table class="table table-hover">
<tr class="danger">
<td>编号</td>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>操作</td>
</tr>
<c:forEach items="${ books }" var="s">
<tr>
<td>${ s.id }</td>
<td>${ s.title }</td>
<td>${ s.price }</td>
<td>${ s.author }</td>
<td><a href="del.do?id=${ s.id }">删除</a>|<a href="aa.do?id=${ s.id }">修改</a></td>
</tr>
</c:forEach>
五、三层架构
1、什么是三层架构
三层架构:就是将整个业务划分为三层:表示层、业务逻辑层、数据库访问层
表示层:主要是指与用户交互的界面,用于接收用户输入的数据和显示处理后用户所需要的数据
业务逻辑层:表示层和数据库访问层之间的桥梁,实现业务逻辑,具体包含:验证、计算、业务规划等等
数据库访问层:与数据库打交道,主要实现对数据的增、删、改、查
注意:entity(实体类) 它不属于三层之中的任何一层,但是它贯穿于三层,能在三层之间传递数据
2、层与层之间的关系
3、怎么理解三层架构
服务员:只管接待客人
厨师:只管做客人点的菜
采购员:只管按要求采购食材
4、为什么需要三层架构
区分层次的目的是为了“高内聚,低耦合”的思想
高内聚:尽可能类的每个成员方法只完成一件事
低耦合:减少类内部,一个成员方法调用另一个成员方法
从类角度来看,高内聚低耦合:减少类内部,对其他类的调用
从功能块来看,高内聚低耦合:减少模块之间的交互复杂度
简单来说,就是解耦:只做自己功能内的事
他们各施其职,服务员不用不用了解厨师如何做菜,不用了解采购员如何采购食材;厨师不用知道服务员接待了哪位客人,不用知道采购员如何采购食材;同样,采购员不用知道服务员接待了哪位客人,不用知道厨师如何做菜。
任何一层发生变法都不会影响其它层:
服务员(表示层):请假——另找服务员;
厨师(业务逻辑层):辞职——招聘另一个厨师;
采购员(数据库访问层):辞职——招聘另一个采购员;
5、两层与三层的区别
两层:当一个地方发生变化时,都需要重新开发整个系统。“多层”放在一层,分工不明确耦合度高,难以适应需求变化,可维护性低】可扩展性低
三层:发生在哪一层的变化,只需要更改该层,不需要更改整个系统。层次清晰,分工明确,每层之间的耦合度低——提高了效率,适应需求变化,可维护性高,可扩展性高
6、现状分析
我们目前是直接在表示层(servlet)调用了数据访问层dao(相当于服务员直接找到了采购员),不合适!
因此,我们应该增加业务逻辑层biz,在servlet中调用biz,biz中调用dao
7、面向接口编程
旨在将设计与实现完全分离
在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。
8、使用三层架构实现登录功能
//接口:只做设计,不做实现
public interface IUserDao {//IUserBiz
public User login(String uname,String upwd);
}
/**
* 数据访问层
*/
public class UserDao implements IUserDao{
//在这个类里 以前怎么写dao方法 现在仍然怎么写
//实现类 专门做实现
private Connection con=null;
private ResultSet rs=null;
private PreparedStatement ps=null;
public User login(String uname,String upwd) {
User u=null;
try {
con=DBHelper.getCon();
String sql="select * from tb_user where uname=? and upwd=?";
ps=con.prepareStatement(sql);
ps.setString(1, uname);
ps.setString(2, upwd);
rs=ps.executeQuery();
if(rs.next()) {
u=new User(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getString(4));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBHelper.close(con, ps, rs);
}
return u;
}
}
/**
* 业务逻辑层
*/
public class UserBiz implements IUserBiz {
//调用 数据访问层(里氏替换原则)
IUserDao iud=new UserDao();
}
/**
* 表示层
*/
protected void doPost(HttpServletRequest req, HttpServletResponse resp){
//调用 业务逻辑层(里氏替换原则)
IUserBiz iub=new UserBiz();
}
9、三层架构命名方式
六、购物车实现
1、实现购物车的方式
1、Cookie
- 优点:Cookie是存储在客户端的,占用很少的资源,可以减轻服务器压力
- 缺点:基于Cookie开发的购物车要求用户浏览器必须支持并设置为启用Cookie,否则购物车则失效,如果换一台机器再去登录的话,就会丢失购物车信息
2、session
- 优点:session可以于客户端保持同步,不依赖于客户端的设置,它是存储在服务器端的信息,因此比较安全
- 缺点:session会占用服务器资源,加大服务器负荷,会话具有时效性,一旦超时,购物车中商品信息会丢失
3、数据库
- 优点:持久化储存,可以分析用户购买行为
- 缺点:购物车需要实时操作,数据库访问量一旦过大了,就容易导致发生并发或者直接奔溃,维护成本会增加
七、ajax
1、什么是ajax
**Ajax**即**A**synchronous **J**avascript **A**nd **X**ML(异步JavaScript和XML) , 使用Ajax技术网页应用能够快速地将更新呈现在用户界面上,而<font color="red">不需要重载(刷新)整个页面【**只刷新局部**】</font>,这使得程序能够更快地回应用户的操作。
2、为什么需要ajax
在我们之前的开发,每当用户向服务器发送请求,哪怕只是需要更新一点点的局部内容,服务器都会将整个页面进行刷新,这么做的问题有两点:
- 性能会有所降低(一点内容就需要刷新整个庞大的网页)
- 用户的操作页面会中断(整个页面被刷新了)
而我们基于ajax可以使用JavaScript技术向服务器发送异步请求,这可以使我们在不刷新页面的前提下拿到后端数据,完成页面的局部刷新,给用户的感受是在不知不觉中完成请求和响应过程。
3、同步交互和异步交互的区别
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求;
4、基于jQuery实现ajax
1、$.ajax(url,[settings])
url:一个用来包含发送请求的URL字符串
type:请求方式(post或get(默认))
data:发送到服务器的数据,例如:key1=value1&key2=value2或{key1:"value1",key2:"value2"}
dataType:预期服务器返回的数据类型(json,text,xml,hmtl······)
success(daya):请求成功的回调函数 data:服务器返回的数据(响应)
error:请求失败的回调函数
2、$.get/post(url,[data],[callback],[type])
url:发送请求地址
data:待发送key/value参数,例如:key1=value1&key2=value2或{key1:"value1",key2:"value2"}
type:预期服务器返回的数据类型,xml,html,json,text·····
cllback:发送成功时回调函数
八、session&cookie
一、session
1、什么是session?
一个会话就是浏览器与服务器之间的一次通话,包含浏览器与服务器之间的多次请求、响应过程,session对象用来存储有关用户会话的所有信息。
2、session的常用方法
返回类型 | 方法名称 | 说明 |
void | setAttribute(String key,Object value) | 以key/value形式保存对象值 |
Object | getAttribute(String key) | 通过key获取对象值 |
void | setMaxInactivelnterval() | 设置session的有效非活动时间,以秒为单位 |
void | invalidate() | 设置session对象失效 |
String | getId() | 获取session对象的编号 |
二、cookie
1、什么是Cookie?
Cookie的中文意思是“小甜饼”,在互联网中,Cookie是小段的文本信息,在网络服务器上生成,并发送给浏览器。通过使用Cookie可以标识用户身份,记录用户名和密码,跟踪重复用户等。浏览器将Cookie以key/value的形式保存到客户端的某个指定目录中。
基本语法:
//导入包
import="javax.servlet.http.Cookie"
//创建Cookie
Cookie cookie = new Cookie("name","value");
name:用于代表cookie的名称
value:用于表示当前名称所对应的值
//写入Cookie
resp.addCookie(cookie);
cookie常用方法
返回类型 | 方法名称 | 说明 |
void | setMaxAge(int expiry) | 设置Cookie的有效期,以秒为单位 |
void | setValue(String value) | 在Cookie创建后,对Cookie进行赋值 |
String | getValue() | 获取Cookie的值 |
String | getName() | 获取Cookie的名称 |
String | getMaxAge() | 获取Cookie的有效时间,以秒为单位 |
九、过滤器&监听器
一、过滤器
1、什么是过滤器
顾名思义,过滤器就像一张滤网,是处于客户端与服务器目标资源之间的一道过滤技术。
正常来说,客户端发出请求后都会交给servlet;但是如果过滤器存在,客户端发出的请求都是先交给过滤器,然后再交给servlet
2、过滤器的作用
它的主要作用是阻止不合法的请求和非法的访问,可以解决多个servlet共性代码的冗余问题
3、过滤器的实现过程
- 编写java类实现Filter接口,重写三个方法init()、doFilter()、destroy();
- 在doFilter()方法中编写拦截逻辑;
- 设置拦截路径
4、过滤器的拦截路径
通常有三种形式
- 精确拦截匹配,如:/index.jsp /login.jsp
- 后缀拦截匹配,如:*.jsp *.html *.jpg
- 通配符拦截匹配,/*(表示拦截所有)
5、过滤器的运用
web.xml配置
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.zking.filter.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
注意:
web.xml配置方式过滤链的执行顺序跟配置的顺序一致
注解方式过滤链的执行顺序和类名字符排序有关
注解方式
@WebFilter("*.do")
public class EncodingFilter implements Filter{
//转成我们常用的req和resp
HttpServletRequest req=(HttpServletRequest)arg0;
HttpServletResponse resp=(HttpServletResponse)arg1;
//设置编码方式
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html; charset=UTF-8");
//放行
arg2.doFilter(arg0, arg1);
}
二、监听器
servlet监听器,用于监听某个状态变化
1、监听器分类
根据监听对象的类型和范围,将监听器分为3类:
ServletRequest监听器(请求监听器) 域对象request
HttpSession监听器(会话监听) 域对象session
ServletContext监听器(上下文监听器) 域对象application
1.1、servletContext监听【常用】
用于监听web应用启动和销毁的事件,监听器类需要实现servletContextLisetener接口
ServletContext【application】域对象的生命周期;
创建:服务器启动时;
销毁:服务器关闭
该接口的主要方法:
void contextLnitialized(ServletContextEvent se);通知正在接收的对象,应用程序已经被加载及初始化
void contextDestroyed(ServletContextEvent se);通知正在接收的对象,应用程序已经被销毁
servletContextEvent的主要方法:
ServletContext getServletContext();取得当前的ServletContext对象
1.2、httpSession会话监听【偶尔用】
1、HttpSessionListener 监听会话情况
该接口的主要方法:
sessionCreated(HttpSessionEvent se); session创建
sessionDestroyed(HttpSessionEvent se); session销毁
2、HttpSessionAttribyteListener 监听器的操作
该接口的主要方法:
void attributeAdded(HttpSessionBindingEvent se); 监听Http会话中的属性添加
void attributeRemoved(HttpSessionBindingEvent se); 监听Http会话中的属性移除
void attributeReplaced(HttpSessionBindingEvent se); 监听Http会话中的属性更改操作
1.3、servletRequest监听【不用】
用于监听客户端的请求初始化和销毁事件,需要实现ServletRequestListener接口
该接口的主要方法:
requestInitialized(ServletRequestEvent):通知当前对象请求已经被加载及初始化
requestDestroyed(ServletRequestEvent):通知当前对象,请求已经被消除
ServletRequestEvent实例中的方法:
getServletRequest():获取ServletRequest对象
getServletContext():获取ServletContext对象
2、监听器的配置
<!-- web.xml -->
<listener>
<listener-class>com.test.listener.TestHttpSessionListener</listener-class>
</listener>
<!-- 注解方式 -->
@WebListener
问:为什么说session监听器和request监听器一般都不用?
答:以request监听器为例,如果采用request监听,那就意味着每次请求都要触发一次监听,这大大降低了程序的效率,因此很少用。
3、监听器的运用:统计在线用户人数&显示当前用户
思路:
首先需要一个装在线用户的集合,当应用初始化的时候在线用户集合初始化,数量为0,存起来
每次登录成功(session属性添加)的时候,取出集合,把用户加入集合,再把集合存起来
注销的时候,取出集合,把用户移除集合,再把集合存起来
1、Listener
@WebListener
public class CountListener implements ServletContextListener,HttpSessionListener,HttpSessionAttributeListener{
private ServletContext application;
@Override
public void contextDestroyed(ServletContextEvent arg0) {
//System.out.println("应用被销毁了");
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
//应用被初始化拿到application对象
application = arg0.getServletContext();
//实例化保存用户名的集合
List<String> ls=new ArrayList<String>();
//存起来
application.setAttribute("ls",ls);
application.setAttribute("count", ls.size());
}
@Override
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("会话被创建了");
}
@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("会话被销毁了");
//先拿集合
List<String> ls=(List<String>)application.getAttribute("ls");
//拿到当前的用户
User u = (User)arg0.getSession().getAttribute("user");
//将其从集合中移除
ls.remove(u.getUname());
//重新存起来
application.setAttribute("ls",ls);
application.setAttribute("count", ls.size());
}
@Override
public void attributeAdded(HttpSessionBindingEvent arg0) {
//先拿集合
List<String> ls=(List<String>)application.getAttribute("ls");
//拿当前用户
User u = (User)arg0.getSession().getAttribute("user");
//假设法
boolean f=false;
for (String s : ls) {
//如果存在
if(s.equals(u.getUname())) {
f=true;
break;
}
}
if(f==false) {//不存在才加进去
ls.add(u.getUname());
}
//重新存起来
application.setAttribute("ls",ls);
application.setAttribute("count", ls.size());
}
@Override
public void attributeRemoved(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void attributeReplaced(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
}
2、servlet
HttpSession session = req.getSession();//拿到session
session.invalidate();//让session失效
resp.sendRedirect("login.jsp");//跳转到login.jsp
3、jsp
<h2>欢迎${user.uname},这是主界面</h2>
<div style="font-size: 20px;color:red;">当前在线用户:
<c:forEach items="${ls}" var="i">
${i}
</c:forEach>
</div>
<h2>在线人数:${count}人</h2>
十、富文本编辑器
富文本编辑器(Rich Text Editor)是一种允许用户以更直观、更易于理解的方式编辑文本的工具。 与传统的纯文本编辑器不同,富文本编辑器为用户提供了多种格式化选项,如字体、颜色、大小、对齐方式、列表、链接、图片等。 这意味着,你可以轻松地创建出丰富、有吸引力的内容,而无需去记住复杂的HTML代码。
CKEditor
Ckeditor也是一款非常经典的富文本编辑器,官方下载量过千万。它是在非常著名的FCkEditor基础上开发的新版本,FckEditor的用户现在基本都转移到Ckeditor了。
Ckeditor有高性能的实时预览,它特有行内编辑功能,使得编辑内容更加直观,仿佛是在编辑网页一样,有很强的可扩展性,被各大网站广泛运用。
更多介绍及下载:https://ckeditor.com/
十一、文件上传
就是将本地文件上传到服务器,并且可以在服务器进行访问
文章一:https://cloud.tencent.com/developer/article/1475522
文章二:https://blog.youkuaiyun.com/qq_21223653/article/details/107797667