Javaweb三大组件:Servlet程序、Filter过滤器、Listener监听器
三大组件启动顺序:Listener-->Filter-->Servlet
1、执行 Servlet 构造器方法
2、执行 init 初始化方法 第一、二步,是在第一次访问,的时候创建 Servlet 程序会调用
3、执行 service 方法 第三步,每次访问都会调用
4、执行 destroy 销毁方法 第四步,在 web工程停止的时候调用
每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会把请求过来的 HTTP 协议信息解析好封装到 Request 对象中。然后传递到 servlet 方法(doGet 和 doPost)中给我们使用。我们可以通过 HttpServletRequest 对象,获取到所有请求的信息。
i. getRequestURI() 获取请求的资源路径
ii. getRequestURL() 获取请求的统一资源定位符(绝对路径)
iii. getRemoteHost() 获取客户端的 ip 地址
iv. getHeader() 获取请求头
v. getParameter() 获取请求的参数
vi. getParameterValues() 获取请求的参数(多个值的时候使用)
vii. getMethod() 获取请求的方式 GET 或 POST
viii. setAttribute(key, value); 设置域数据
ix. getAttribute(key); 获取域数据
x. getRequestDispatcher() 获取请求转发对象
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
// 获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobby = req.getParameterValues("hobby");
System.out.println(" 用户名:" + username);
System.out.println(" 密码:" + password);
System.out.println(" 兴趣爱好:" + Arrays.asList(hobby));
}
}
doGet请求中文乱码处理
// 获取请求参数
String username = req.getParameter("username");
//1 先以 iso8859-1 进行编码
//2 再以 utf-8 进行解码
username = new String(username.getBytes("iso-8859-1"), "UTF-8");
doPost请求中文乱码处理
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
// 设置请求体的字符集为 UTF-8 ,从而解决 post 请求的中文乱码问题
req.setCharacterEncoding("UTF-8");
System.out.println("-------------doPost------------");
// 获取请求参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String[] hobby = req.getParameterValues("hobby");
System.out.println(" 用户名:" + username);
System.out.println(" 密码:" + password);
System.out.println(" 兴趣爱好:" + Arrays.asList(hobby));
}
请求转发是指,服务器收到请求后,从一次资源跳转到另一个资源的操作叫请求转发。
Title
这是 a 下的 b 下的 c.html 页面
跳回首页
在 javaWeb 中,路径分为相对路径和绝对路径两种:
相对路径是:
. 表示当前目录
.. 表示上一级目录
资源名 表示当前目录/资源名
绝对路径是:
http://ip:port/工程路径/资源路径
在实际开发中,路径都使用绝对路径,而不简单地使用相对路径。
1、绝对路径
2、base+相对
在 web 中 / 斜杠 是一种绝对路径。
斜杠
/servlet1
servletContext.getRealPath(“/”);
request.getRequestDispatcher(“/”);
特殊情况: response.sendRediect(“/”); 把斜杠发送给浏览器解析,得到 http://ip:port/ 。
HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来,Tomcat 服务器都会创建一个 Response 对象传递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息。需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象来进行设置。
字节流 getOutputStream(); 常用于下载(传递二进制数据)
字符流 getWriter(); 常用于回传字符串(常用)
注意: 两个流同时只能使用一个。使用了字节流,就不能再使用字符流,反之亦然,否则就会报错。
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println( resp.getCharacterEncoding() );//默认ISO-8859-1
// // 设置服务器字符集为UTF-8
// resp.setCharacterEncoding("UTF-8");
// // 通过响应头,设置浏览器也使用UTF-8字符集
// resp.setHeader("Content-Type", "text/html; charset=UTF-8");
// 它会同时设置服务器和客户端都使用UTF-8字符集,还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8");
// System.out.println( resp.getCharacterEncoding() );
// 要求 : 往客户端回传 字符串 数据。
PrintWriter writer = resp.getWriter();
writer.write("春江潮水连海平!");
}
}
推荐使用该方式:
// 它会同时设置服务器和客户端都使用 UTF-8 字符集,还设置了响应头
// 此方法一定要在获取流对象之前调用才有效
resp.setContentType("text/html; charset=UTF-8");
客户端给服务器发请求,服务器给客户端新地址,让客户端去新地址访问,叫请求重定向(因为之前的地址可能已经被废弃)。
请求重定向推荐使用:resp.sendRedirect("http://localhost:8080");
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("曾到此一游 Response1 ");
req.setAttribute("key1", "value1");
// 设置响应状态码302 ,表示重定向,(已搬迁)
// resp.setStatus(302);
// 设置响应头,说明 新的地址在哪里
// resp.setHeader("Location", "http://localhost:8080/07_servlet/response2");
// resp.setHeader("Location", "http://localhost:8080");
//推荐使用
resp.sendRedirect("http://localhost:8080");
}
}
MVC 的理念是将软件代码拆分成为组件,单独开发,组合使用( 目的还是为了降低耦合度)。MVC 全称:Model 模型、 View 视图、 Controller 控制器。
jsp 的全称是 java server pages,是java 的服务器页面。主要作用是代替 Servlet 程序回传 html 页面的数据。jsp页面本质上是一个servlet程序。
域对象可以存取数据
四个域在使用的时候,优先顺序是从小到大的范围的顺序:
pageContext ——> request——> session——> application
由于 jsp 翻译之后,底层源代码都是使用 out 来进行输出,所以一般情况下在 jsp 页面中统一使用 out 来进行输出,避免打乱页面输出内容的顺序。
out.write() 输出字符串没有问题
out.print() 输出任意数据都没有问题(原因:都转换成为字符串后调用的 write 输出)
深入源码,浅出结论:在 jsp 页面中,可以统一使用 out.print()来进行输出。
EL 表达式的全称是:Expression Language,是表达式语言。
作用:EL 表达式主要是代替 jsp 页面中的表达式脚本在 jsp 页面中进行数据的输出。
EL 表达式在输出数据的时候,要比 jsp 的表达式脚本要简洁很多。
EL 表达式的格式是:${表达式}
EL 表达式在输出 null 值的时候,输出的是空串。jsp 表达式脚本输出 null 值的时候,输出的是 null 字符串。(EL表达式的优势!null多难看!)
EL 表达式主要是在 jsp 页面中输出域对象中的数据。当四个域中都有相同的 key 的数据的时候,EL 表达式会按照四个域的从小到大的顺序去进行搜索,找到就输出。
JSTL 标签库 全称是指 JSP Standard Tag Library JSP 标准标签库,是一个不断完善的开放源代码的 JSP 标签库。EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库则是为了替换代码脚本,这样使得整个 jsp 页面变得更加简洁。
1. 先导入 jstl 标签库的 jar 包。
taglibs-standard-impl-1.2.1.jar
taglibs-standard-spec-1.2.1.jar
2. 使用 taglib 指令引入标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
保存之前:${ sessionScope.abc }
保存之后:${ sessionScope.abc }
<%--
ii.
if 标签用来做 if 判断。
test 属性表示判断的条件(使用 EL 表达式输出)
--%>
12 等于 12
12 不等于 12
<%--
iii. 标签
作用:多路判断。跟 switch ... case .... default 非常接近
choose 标签开始选择判断
when 标签表示每一种判断情况
test 属性表示当前这种判断情况的值
otherwise 标签表示剩下的情况
标签使用时需要注意的点:
1 、标签里不能使用 html 注释,要使用 jsp 注释
2 、 when 标签的父标签一定要是 choose 标签
--%>
<%
request.setAttribute("height", 180);
%>
小巨人
很高
还可以
大于 160
大于 150
大于 140
其他小于 140
第${i}行
<%
request.setAttribute("arr", new String[{"18610541354","18688886666","18699998888"});
%>
${ item }
<%
Map map = new HashMap();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
request.setAttribute("map", map);
%>
${entry.key} = ${entry.value}
<%
List studentList = new ArrayList();
for (int i = 1; i <= 10; i++) {
studentList.add(new Student(i,"username"+i ,"pass"+i,18+i,"phone"+i));
}
request.setAttribute("stus", studentList);
%>
编号
用户名
密码
年龄
电话
操作
${stu.id}
${stu.username}
${stu.password}
${stu.age}
${stu.phone}
${status.step}
import java.util.List;
/**
* Page是分页的模型对象
* @param 是具体的模块的javaBean类
*/
public class Page {
public static final Integer PAGE_SIZE = 4;
// 当前页码
private Integer pageNo;//用Integer而不用int的原因:包装类的默认值直接为null
// 总页码
private Integer pageTotal;
// 当前页显示数量
private Integer pageSize = PAGE_SIZE;
// 总记录数
private Integer pageTotalCount;
// 当前页数据
private List items;
// 分页条的请求地址
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
/* 数据边界的有效检查 */
if (pageNo < 1) {
pageNo = 1;
}
if (pageNo > pageTotal) {
pageNo = pageTotal;
}
this.pageNo = pageNo;
}
public Integer getPageTotal() {
return pageTotal;
}
public void setPageTotal(Integer pageTotal) {
this.pageTotal = pageTotal;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getPageTotalCount() {
return pageTotalCount;
}
public void setPageTotalCount(Integer pageTotalCount) {
this.pageTotalCount = pageTotalCount;
}
public List getItems() {
return items;
}
public void setItems(List items) {
this.items = items;
}
@Override
public String toString() {
return "Page{" +
"pageNo=" + pageNo +
", pageTotal=" + pageTotal +
", pageSize=" + pageSize +
", pageTotalCount=" + pageTotalCount +
", items=" + items +
", url='" + url + '\'' +
'}';
}
}
xxxDaoImpl:
@Override
public Integer queryForPageTotalCount() {
String sql = "select count(*) from t_book";
Number count = (Number) queryForSingleValue(sql);
return count.intValue();
}
@Override
public List queryForPageItems(int begin, int pageSize) {
String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imgPath from t_book limit ?,?";
return queryForList(Book.class,sql,begin,pageSize);
}
xxxServiceImpl:
@Override
public Page page(int pageNo, int pageSize) {
Page page = new Page();
// 设置每页显示的数量
page.setPageSize(pageSize);
// 求总记录数
Integer pageTotalCount = bookDao.queryForPageTotalCount();
// 设置总记录数
page.setPageTotalCount(pageTotalCount);
// 求总页码
Integer pageTotal = pageTotalCount / pageSize;
if (pageTotalCount % pageSize > 0) {
pageTotal += 1;
}
// 设置总页码
page.setPageTotal(pageTotal);
// 设置当前页码
page.setPageNo(pageNo);
// 求当前页数据的开始索引
int begin = (page.getPageNo() - 1) * pageSize;
// 求当前页数据
List items = bookDao.queryForPageItems(begin, pageSize);
// 设置当前页数据
page.setItems(items);
return page;
}
xxxServlet:
public abstract class BaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决post请求中文乱码问题
// 一定要在获取请求参数之前调用才有效
req.setCharacterEncoding("UTF-8");
String action = req.getParameter("action");
try {
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// System.out.println(method);
// System.out.println(this);
// 调用目标业务 方法
method.invoke(this, req, resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class XxxServlet extends BaseServlet{
private XxxService xxxService = new XxxServiceImpl();
/**
* 处理分页
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、获取请求的参数 pageNo , pageSize
int pageNo = WebUtils.parseInt(req.getParameter("pageNo"),1);
int pageSize = WebUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);
//2. 调用XxxService.page(pageNo,pageSize),得到Page对象
Page page = xxxService.page(pageNo,pageSize);
page.setUrl("manager/xxxServlet?action=page");
//3. 保存Page对象到Request域中
req.setAttribute("page",page);
//4. 请求转发到pages/manager/book_manager.jsp
req.getRequestDispatcher("/pages/manager/xxx_manager.jsp").forward(req,resp);
}
}
public class WebUtils {
/**
* 将字符串转换成为int类型的数据
*
* @param strInt
* @param defaultValue
* @return
*/
public static int parseInt(String strInt, int defaultValue) {
try {
return Integer.parseInt(strInt);
} catch (NumberFormatException e) {
// e.printStackTrace();
}
return defaultValue;
}
}
分页条page_nav.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--分页条的开始--%>
<%--分页条的结束--%>
<%--静态包含分页条--%>
<%@include file="/pages/common/page_nav.jsp"%>
Session 在服务器端,Cookie 在客户端(浏览器)。【如:Cookie用来自动登录,Session用来保持登录状态】
session机制:
客户端第一次请求服务端时,服务端会产生一个session对象(用于保存该客户的信息),并且每个session对象都会有一个唯一的 sessionId( 用于区分其他session);服务端会产生一个cookie,并且该cookie的name=JSESSIONID ,value=服务端sessionId的值。然后服务端会在响应客户端的同时将该cookie发送给客户端,至此客户端就有了 一个cookie(JSESSIONID)。因此,客户端的cookie就可以和服务端的session一一对应(JSESSIONID - sessionID)
客户端第二/n次请求服务端时,服务端会先用客户端cookie中的JSESSIONID去服务端的session中匹配sessionid,如果匹配成功(cookie 的 jsessionid和sesion 的 sessionid),
说明此用户不是第一次访问,无需登录。举例:
客户端: 顾客(客户端)
服务端: 存包处 - 商场(服务端)顾客第一次存包:商场 判断此人是 之前已经存过包(通过你手里是否有钥匙)。
如果是新顾客(没钥匙) ,分配一个钥匙给该顾客; 钥匙 会和 柜子 一一对应;第二/n次 存包:商场 判断此人是 之前已经存过包(通过你手里是否有钥匙)
如果是老顾客(有钥匙),则不需要再分配;该顾客手里的钥匙会和柜子自动一一对应。
kaptcha-2.3.2.jar
KaptchaServlet
com.google.code.kaptcha.servlet.KaptchaServlet
KaptchaServlet
/kaptcha.jpg
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
// 获取 Session 中的验证码
String token = (String) req.getSession().getAttribute(KAPTCHA_SESSION_KEY);
// 删除 Session 中的验证码
req.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
String code = req.getParameter("code");
// 获取用户名
String username = req.getParameter("username");
if (token != null && token.equalsIgnoreCase(code)) {
System.out.println("保存到数据库:" + username);
resp.sendRedirect(req.getContextPath() + "/ok.jsp");
} else {
System.out.println("请不要重复提交表单");
}
}
// 给验证码的图片,绑定单击事件
$("#code_img").click(function () {
// 在事件响应的 function 函数中有一个 this 对象。这个 this 对象,是当前正在响应事件的 dom 对象
// src 属性表示验证码 img 标签的 图片路径。它可读,可写
// alert(this.src);
this.src = "${basePath}kaptcha.jpg?d=" + new Date();
//new Date()相当于一个永远不一样的随机数,用于图片刷新,跳过缓存
})
Filter 过滤器它是 JavaWeb 的三大组件之一,它的作用是:拦截请求,过滤响应。拦截请求常见的应用场景有:权限检查、日志操作、事务管理等等。
Filter代码:
public class AdminFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* doFilter方法专门用于拦截请求,过滤响应。可以做【权限检查】
* @param servletRequest
* @param servletResponse
* @param filterChain
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
Object user = session.getAttribute("user");
if(user == null) {//若用户没有登录,则跳到登录页面
servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);
return;
}else{//让程序继续访问用户的目标资源
filterChain.doFilter(servletRequest,servletResponse);
}
}
@Override
public void destroy() {
}
}
配置web.xml:
AdminFilter
com.atguigu.filter.AdminFilter
AdminFilter
/admin/*
按照web.xml中配置filter的顺序执行(下图为先配置的Filter1):
/target.jsp 以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/target.jsp
/admin/* 以上配置的路径,表示请求地址必须为:http://ip:port/工程路径/admin/*
*.html 以上配置的路径,表示请求地址必须以.html 结尾才会拦截到
*.do 以上配置的路径,表示请求地址必须以.do 结尾才会拦截到
*.action 以上配置的路径,表示请求地址必须以.action 结尾才会拦截到
注意:Filter 过滤器只关心请求的地址是否匹配,不关心请求的资源是否存在!!!
ThreadLocal 可以解决多线程的数据安全问题。 ThreadLocal 可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数组,集合)
ThreadLocal 的特点:
JdbcUtils工具类修改为:
public class JdbcUtils {
private static DruidDataSource dataSource;
private static ThreadLocal conns = new ThreadLocal();
static {
try {
Properties properties = new Properties();
// 读取 jdbc.properties属性配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
// 从流中加载数据
properties.load(inputStream);
// 创建 数据库连接 池
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接池中的连接
*
* @return 如果返回null, 说明获取连接失败
有值就是获取连接成功
*/
public static Connection getConnection() {
Connection conn = conns.get();
if (conn == null) {
try {
conn = dataSource.getConnection();//从数据库连接池中获取连接
conns.set(conn);//将获取到的连接conn保存到ThreadLocal对象中,供后面的JDBC对象使用
conn.setAutoCommit(false);//设置手动提交事务
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
/**
* 提交事务并关闭释放连接
*/
public static void commitAndClose() {
Connection connection = conns.get();
if (connection != null) {//如果获取到的connection不是null,说明之前使用过该连接操作数据库
try {
connection.commit();//提交事务
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();//关闭连接,资源
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//一定要执行remove操作!!!否则会出错(Tomcat服务器底层使用了线程池技术)
conns.remove();
}
/**
* 回滚事务并关闭释放连接
*/
public static void rollbackAndClose() {
Connection connection = conns.get();
if (connection != null) {//如果获取到的connection不是null,说明之前使用过该连接操作数据库
try {
connection.rollback();//回滚事务
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();//关闭连接,资源
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//一定要执行remove操作!!!否则会出错(Tomcat服务器底层使用了线程池技术)
conns.remove();
}
}
BaseDao修改为:(在每一个catch抛出运行时异常给需要的地方捕获处理!)
public abstract class BaseDao {
//使用DbUtils操作数据库
private QueryRunner queryRunner = new QueryRunner();
/**
* update() 方法用来执行:Insert\Update\Delete语句
*
* @return 如果返回-1,说明执行失败
返回其他表示影响的行数
*/
public int update(String sql, Object... args) {
System.out.println("BaseDao在【"+Thread.currentThread().getName()+"】中");
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.update(connection, sql, args);
} catch (SQLException e) {
e.printStackTrace();
//把异常往外抛。因为不在DAO层关闭connection了,就需要在提交事务(或者回滚)并关闭连接的地方捕获异常
//如果不抛出去,需要的地方捕获不到异常
throw new RuntimeException(e);
}
}
/**
* 查询返回一个javaBean的sql语句
*
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param 返回的类型的泛型
* @return
*/
public T queryForOne(Class type, String sql, Object... args) {
Connection con = JdbcUtils.getConnection();
try {
return queryRunner.query(con, sql, new BeanHandler(type), args);
} catch (SQLException e) {
e.printStackTrace();
//把异常往外抛。因为不在DAO层关闭connection了,就需要在提交事务(或者回滚)并关闭连接的地方捕获异常
//如果不抛出去,需要的地方捕获不到异常
throw new RuntimeException(e);
}
}
/**
* 查询返回多个javaBean的sql语句
*
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param 返回的类型的泛型
* @return
*/
public List queryForList(Class type, String sql, Object... args) {
Connection con = JdbcUtils.getConnection();
try {
return queryRunner.query(con, sql, new BeanListHandler(type), args);
} catch (SQLException e) {
e.printStackTrace();
//把异常往外抛。因为不在DAO层关闭connection了,就需要在提交事务(或者回滚)并关闭连接的地方捕获异常
//如果不抛出去,需要的地方捕获不到异常
throw new RuntimeException(e);
}
}
/**
* 执行返回一行一列的sql语句
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @return
*/
public Object queryForSingleValue(String sql, Object... args){
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn, sql, new ScalarHandler(), args);
} catch (SQLException e) {
e.printStackTrace();
//把异常往外抛。因为不在DAO层关闭connection了,就需要在提交事务(或者回滚)并关闭连接的地方捕获异常
//如果不抛出去,需要的地方捕获不到异常
throw new RuntimeException(e);
}
}
}
TransactionFilter 类代码:
public class TransactionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(servletRequest,servletResponse);
JdbcUtils.commitAndClose();
} catch (Exception e) {
JdbcUtils.rollbackAndClose();
e.printStackTrace();
throw new RuntimeException(e);//把异常抛给Tomcat管理,展示出错后的友好界面
}
}
@Override
public void destroy() {
}
}
web.xml 中的配置:
TransactionFilter
com.atguigu.filter.TransactionFilter
TransactionFilter
/*
把 BaseServlet 中的异常往外抛给 Filter 过滤器:(在catch中抛出运行时异常)
public abstract class BaseServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 解决post请求中文乱码问题
// 一定要在获取请求参数之前调用才有效
req.setCharacterEncoding("UTF-8");
//解决中文响应乱码
resp.setContentType("text/html;charset=UTF-8");
String action = req.getParameter("action");
try {
// 获取action业务鉴别字符串,获取相应的业务 方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// System.out.println(method);
// System.out.println(this);
// 调用目标业务 方法
method.invoke(this, req, resp);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);//把异常抛给Filter过滤器
}
}
}
在web.xml中配置:
404
/pages/error/error404.jsp
500
/pages/error/error500.jsp
JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式(轻量级指的是跟 xml 做比较;数据交换指的是客户端和服务器之间业务数据的传递格式),易于阅读和编写,同时也易于机器解析和生成。JSON 采用完全独立于语言的文本格式,而且很多语言都提供了对 json 的支持(包括 C, C++, C#, Java, JavaScript, Perl, Python 等), 这样就使得 JSON 成为理想的数据交换格式。
json 是由键值对组成,并且由花括号(大括号)包围。每个键由引号引起来,键和值之间使用冒号进行分隔, 多组键值对之间用逗号进行分隔。
JSON定义及访问:
json 的存在有两种形式:
一种以对象的形式存在,称为 json 对象
一种以字符串的形式存在,称为 json 字符串。
要操作 json 中的数据时,需要 json 对象的格式;
要在客户端和服务器之间进行数据交换的时候,使用 json 字符串。
- JSON.stringify() 把 json 对象转换成为 json 字符串
- JSON.parse() 把 json 字符串转换成为 json 对象
1. javaBean 和 json 的互转
@Test
public void test1(){
Person person = new Person(1,"周涛");
// 创建Gson对象实例
Gson gson = new Gson();
// toJson方法可以把java对象转换成为json字符串
String personJsonString = gson.toJson(person);
System.out.println("personJsonString"+personJsonString);
// fromJson把json字符串转换回Java对象
// 第一个参数是json字符串
// 第二个参数是转换回去的Java对象类型
Person person1 = gson.fromJson(personJsonString, Person.class);
System.out.println(person1);
}
2. List和json的互转
@Test
public void test2() {
List personList = new ArrayList<>();
personList.add(new Person(1, "周涛"));
personList.add(new Person(2, "总监"));
Gson gson = new Gson();
// 把List转换为json字符串
String personListJsonString = gson.toJson(personList);
System.out.println("personListJsonString:"+personListJsonString);
// List list = gson.fromJson(personListJsonString, new PersonListType().getType());
//不创建获取list类的方法直接使用匿名类对象
List list = gson.fromJson(personListJsonString, new TypeToken>(){}.getType());
System.out.println(list);
Person person = list.get(0);
System.out.println(person);
}
3. Map和json的互转
@Test
public void test3(){
Map personMap = new HashMap<>();
personMap.put(1, new Person(1, "周涛"));
personMap.put(2, new Person(2, "总监"));
Gson gson = new Gson();
// 把 map 集合转换成为 json字符串
String personMapJsonString = gson.toJson(personMap);
System.out.println("personMapJsonString:"+personMapJsonString);
// Map personMap2 = gson.fromJson(personMapJsonString, new PersonMapType().getType());
//使用匿名内部类 匿名对象
Map personMap2 = gson.fromJson(personMapJsonString, new TypeToken>(){}.getType());
System.out.println(personMap2);
Person p = personMap2.get(1);
System.out.println(p);
}
AJAX 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。 ajax 是一种浏览器通过 js 异步发起请求,局部更新页面的技术。 ajax 请求的局部更新,浏览器地址栏不会发生变化,局部更新不会舍弃原来页面的内容。
1. $.ajax 方法
url 表示请求的地址
type 表示请求的类型 GET 或 POST 请求
data 表示发送给服务器的数据 格式有两种:
一:name=value&name=value
二:{key:value}
success 请求成功,响应的回调函数
dataType 响应的数据类型
常用的数据类型有:
text 表示纯文本
xml 表示 xml 数据
json 表示 json 对象
// ajax请求
$("#ajaxBtn").click(function () {
$.ajax({
url: "http://localhost:8080/16_json_ajax__il8n/ajaxServlet",
// data:"action=jQueryAjax",
data: {action: "jQueryAjax"},
type: "GET",
success: function (data) {
alert("服务器返回的数据是" + data);
// var jsonObj = JSON.parse(data);要把传回来的json字符串转为json对象
// $("#msg").html("编号:"+jsonObj.id+",姓名:"+jsonObj.name);
$("#msg").html("ajax 编号:" + data.id + ",姓名:" + data.name);
},
// dataType:"text"//设置传回来的数据类型为text文本类型
dataType: "json"//设置传回来的数据类型为json对象,可以直接取值
});
alert("ajax btn");
});
2. $.get 方法和$.post 方法
url 请求的 url 地址
data 发送的数据
callback 成功的回调函数
type 返回的数据类型
// ajax--get请求
$("#getBtn").click(function () {
$.get("http://localhost:8080/16_json_ajax__il8n/ajaxServlet", "action=jQueryGet", function (data) {
$("#msg").html("get 编号:" + data.id + ",姓名:" + data.name);
}, "json");
alert(" get btn ");
});
// ajax--post请求
$("#postBtn").click(function () {
$.post("http://localhost:8080/16_json_ajax__il8n/ajaxServlet", "action=jQueryPost", function (data) {
$("#msg").html("post 编号:" + data.id + ",姓名:" + data.name);
}, "json");
alert("post btn");
});
3. $.getJSON 方法
url 请求的 url 地址
data 发送给服务器的数据
callback 成功的回调函数
// ajax--getJson请求
$("#getJSONBtn").click(function () {
$.getJSON("http://localhost:8080/16_json_ajax__il8n/ajaxServlet", "action=jQueryGetJSON", function (data) {
$("#msg").html("getJSON 编号:" + data.id + ",姓名:" + data.name);
});
alert("getJSON btn");
});
表单序列化方法serialize()可以把表单中所有表单项的内容都获取到,并以name=value&name=value的形式进行拼接。
// ajax请求 把参数序列化
$("#submit").click(function () {
alert($("#form01").serialize());
$.getJSON("http://localhost:8080/16_json_ajax__il8n/ajaxServlet", "action=jQuerySerialize&" + $("#form01").serialize(), function (data) {
$("#msg").html("jQuerySerialize 编号:" + data.id + ",姓名:" + data.name);
});
alert("serialize()");
});