黑马程序员技术交流社区
标题: web_java项目的知识点 [打印本页]
作者: 腾云科技 时间: 2018-7-13 14:27
标题: web_java项目的知识点
本帖最后由 腾云科技 于 2018-7-13 17:44 编辑
1.多个请求共用一个Servlet
我们在对JavaWEB工程进行开发的时候,我们经常会遇到这样一个问题,在jsp中发送到Servlet的每一个请求都要写一个对应的Servlet,这样会造成一个工程完成下来需要写几十个Servlet,那么怎么可以做到多个请求共用一个Servlet呢?
一、利用反射原理(根据获取到的url-pattern,截取出相应的方法名,进而调用相应的方法)
1.配置web.xml文件,<url-pattern>中设置以 *.扩展名 的方式进行匹配(下面的例子以 *.do 匹配,调用的Servlet为 StaffServlet,对Staff表的查询query 和删除delete 请求进行处理)
[XML] 纯文本查看 复制代码
<servlet>
<servlet-name>StaffServlet</servlet-name>
<servlet-class>cn.edu.lingnan.servlet.StaffServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StaffServlet</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
所有以 .do 结尾的请求都会调用StaffServlet
2.编写Servlet(例子:StaffServlet)
[Java] 纯文本查看 复制代码
public class StaffServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取能够与"url-pattern"中匹配的路径
String method = request.getServletPath();
//(此时处理的请求是查询 query.do)
System.out.println("request.getServletPath()获取的值为: " + method);//输出 /query.do
//2.通过字符串截取,把方法名 query 截取出来
method = method.substring(1, method.length()-3);
System.out.println("截取后的值为: "+ method);
Method m = null;
try {
//3.获取当前类中名字为 method 的方法
m = this.getClass().getDeclaredMethod(method,HttpServletRequest.class, HttpServletResponse.class);
//4.调用 method 方法
m.invoke(this, request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
private void query(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("query方法被调用");
}
private void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("delete方法被调用");
}
}
3. jsp 中发送请求调用servlet
[HTML] 纯文本查看 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="query.do">这是一个查询请求,调用Servlet中的query方法</a>
<br>
<br>
<a href="delete.do">这是一个删除请求,调用Servlet中的delete方法</a>
</body>
</html>
注意:url-pattern 中的扩展名可以是任意字符,不一定要是 .do , 例如也可以是 .doStaff , 但是改了扩展名了要注意修改截取的字符串的位置,如修改由.do 修改为 .doStaff 时,doPost中
method = method.substring(1, method.length()-3);需修改为(.do 为三个字符)
method = method.substring(1, method.length()-8);(.doStaff 为八个字符)
jsp 中调用时,则也相应修改 query.do ---> query.doStaff
二、利用URL中的参数传送需要调用的方法名
1.配置web.xml, 映射Servlet路径(以下以 StudentServlet 调用 Servlet 中的 query 和 delete 方法为例子)
[HTML] 纯文本查看 复制代码
<servlet>
<servlet-name>StudentServlet</servlet-name>
<servlet-class>servlet.StudentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>StudentServlet</servlet-name>
<url-pattern>/studentServlet</url-pattern>
</servlet-mapping>
2.编写Servlet(StudentServlet)
[Java] 纯文本查看 复制代码
public class StudentServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数 method
String method = request.getParameter("method");
System.out.println("获取到的method参数为: " + method);
//调用 method 方法
if(method.equals("query")) {
this.query(request, response);
}else {
if(method.equals("delete")) {
this.delete(request, response);
}
}
}
private void query(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("query 方法被调用");
}
private void delete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("delete 方法被调用");
}
}
3. jsp中发送请求调用Servlet
[HTML] 纯文本查看 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="studentServlet?method=query">这是一个查询请求,调用Servlet中的query方法</a>
<br>
<br>
<a href="delete.do?method=delete">这是一个删除请求,调用Servlet中的delete方法</a>
</body>
</html>
2.自动登录的案例:
步骤:
1.创建数据库和表
2.导入jar包和工具类
3.创建包结构及常用类
4.登录功能
5.利用Cookie记住用户名和密码
6.实现自动登录的过滤器
代码书写:
1.index.jsp中判断能否获取到用户信息
[HTML] 纯文本查看 复制代码
<ol class="list-inline">
<c:if test="${ empty user }">
<li><a href="${pageContext.request.contextPath}/login/login.jsp">登录</a></li>
<li><a href="register.htm">注册</a></li>
</c:if>
<c:if test="${ not empty user }">
<li>您好:${ user.nickname }</li>
<li><a href="#">退出</a></li>
</c:if>
<li><a href="cart.htm">购物车</a></li>
</ol>
2.login.jsp中自动登录按钮添加name和value属性
<input type="checkbox" name="autoLogin" value="true"> 自动登录
3.servlet中返回的user实体类是否为空,如果登陆成功,将用户名和密码保存在cookie中,并设置保存时间
[Java] 纯文本查看 复制代码
// 跳转页面:
if(existUser == null){
// 登录失败:
req.setAttribute("msg", "用户名或密码错误!");
req.getRequestDispatcher("/demo5/login.jsp").forward(req, resp);
}else{
// 登录成功:
// 记住用户名和密码:
String autoLogin = req.getParameter("autoLogin");
if("true".equals(autoLogin)){
// 自动登录的复选框已经勾选.
Cookie cookie = new Cookie("autoLogin",existUser.getUsername()+"#"+existUser.getPassword());
cookie.setPath("/day16");
cookie.setMaxAge(60 * 60 * 24 * 7);
resp.addCookie(cookie);
}
// 使用Session记录用户信息.
req.getSession().setAttribute("existUser", existUser);
resp.sendRedirect(req.getContextPath()+"/demo5/index.jsp");
}
4.过滤器Filter中的代码编写:
[Java] 纯文本查看 复制代码
public class AutoLoginFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
/**
* 判断session中是否有用户的信息:
* * session中如果有:放行.
* * session中没有:
* * 从Cookie中获取:
* * Cookie中没有:放行.
* * Cookie中有:
* * 获取Cookie中存的用户名和密码到数据库查询.
* * 没有查询到:放行.
* * 查询到:将用户信息存入到session . 放行.
* /
// 判断session中是否有用户的信息:
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
User existUser = (User) session.getAttribute("existUser");
if(existUser != null){
// session中有用户信息.
chain.doFilter(req, response);
}else{
// session中没有用户信息.
// 获得Cookie的数据:
Cookie[] cookies = req.getCookies();
Cookie cookie = CookieUtils.findCookie(cookies, "autoLogin");
// 判断Cookie中有没有信息:
if(cookie == null){
// 没有携带Cookie的信息过来:
chain.doFilter(req, response);
}else{
// 带着Cookie信息过来.
String value = cookie.getValue();// aaa#111
// 获得用户名和密码:
String username = value.split("#")[0];
String password = value.split("#")[1];
// 去数据库进行查询:
User user = new User();
user.setUsername(username);
user.setPassword(password);
UserService userService = new UserService();
try {
existUser = userService.login(user);
if(existUser == null){
// 用户名或密码错误:Cookie被篡改的.
chain.doFilter(req, response);
}else{
// 将用户存到session中,放行
session.setAttribute("existUser", existUser);
chain.doFilter(req, response);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
//doFilter的简化写法:
[AppleScript] 纯文本查看 复制代码
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession();
User existUser = (User) session.getAttribute("existUser");
if(existUser==null){
Cookie[] cookies = req.getCookies();
Cookie cookie = CookieUtils.findCookie(cookies, "autoLogin");
if(cookie!=null){
String value = cookie.getValue();// aaa#111
// 获得用户名和密码:
String username = value.split("#")[0];
String password = value.split("#")[1];
// 去数据库进行查询:
User user = new User();
user.setUsername(username);
user.setPassword(password);
UserService userService = new UserService();
try {
existUser = userService.login(user);
if(existUser!=null){
session.setAttribute("existUser", existUser);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
chain.doFilter(req, response);
5.web.xml中的配置文件:
[XML] 纯文本查看 复制代码
<filter>
<filter-name>autoLoginFilter</filter-name>
<filter-class>com.itheima_Filter.autoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>autoLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.通用的字符集编码的过滤器案例:
网站上通常会提交带有中文的数据,GET/POST请求都有可能提交中文数据.
通常情况下在Servlet中处理中文乱码.
只需要在Servlet中调用request.getParameter();接收参数就可以,而不去关心到底get/post如何处理乱码.
增强request中的getParameter方法:
继承:控制这个类构造.
装饰者模式:增强的类和被增强类实现相同的接口,增强的类中获得到被增强的类的引用.
缺点:接口中方法太多.
动态代理:被增强的类实现接口就可以.
装饰者模式对request中的getParameter方法增强:
1.HttpServletRequest是接口;
2.HttpServletRequestWrapper是HttpServletRequest的模板实现类,里边的方法全部调用父类的方法
用来让别的类直接继承,增强其中的某一个方法,减少了代码的书写
3.新建一个MyHttpServletRequestWrapper继承HttpServletRequestWrapper
4.新建的My...类,构造方法传入HttpServletRequest request;
private HttpServletRequest request;
public MyHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
5.将HttpServletRequest传入的request赋值给My...的私有成员变量HttpServletRequest request;
6.用被赋值的request重写getParameter(String name);方法即可对这个方法进行增强
7.在filter中创建MyHttpServletRequestWrapper对象,此时的request已经是被增强过的了
8.将被增强过得request通过chain.doFilter方法传给Servlet即可
装饰着模式的层次理解:
被增强的类及对象:ServletRequest request
__________|____________________
| |
实现类HttpServletRequest 模板实现类HttpServletRequestWrapper
对象:req |
|
--创建一个对模板类的的继承类,这样就可以修改那个方法就重写哪个方法
减少代码的书写
|
|
MyHttpServletRequestWrapper
成员变量:private HttpServletRequest request;
--有参构造需要将HttpServletRequest的对象req出入
在构造方法中将req赋值给成员变量request
public MyHttpServletRequestWrapper(HttpServletRequest req) {
super(req);
this.request = request;
}
--在类的内部可以使用request对方法进行增强
|
|
过滤器filter中创建MyHttp...Wrapper的对象MyReq,将其传入到放行方法中
MyHttp...Wrapper MyReq = new MyHttp...Wrapper(Http...request req);
chain.doFilter(myReq, response);
代码实现:
[Java] 纯文本查看 复制代码
//在Filter中的doFilter方法代码书写
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
MyHttpServletRequestWrapper myReq = new MyHttpServletRequestWrapper(req);
chain.doFilter(myReq, response);
}
//装饰者模式增强request的getParameter方法
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper{
private HttpServletRequest request;
public MyHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
// 根据请求方式不同,去处理:
// 获得请求方式:
String method = request.getMethod();
if("get".equalsIgnoreCase(method)){
String value = null;
try {
value = new String(request.getParameter(name).getBytes("ISO-8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return value;
}else if("post".equalsIgnoreCase(method)){
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return super.getParameter(name);
}
}
4.动态代理:
使用动态代理完成字符集编码过滤器的编写:
request中的方法的增强
继承 :能够控制这个类的构造.
装饰者 :增强的类和被增强的类实现相同的接口,增强的类中获得到被增强的类的引用.
接口中方法过多,只增强其中的某个方法.其他的方法也需要重写.
动态代理 :被增强的类实现了接口.
代理的概述
代理:
JDK中动态代理:Proxy对象.
Proxy.newProxyInstance(ClassLoader cl,Class[] interfaces,InvocationHandler ih);
动态代理入门案例:
[Java] 纯文本查看 复制代码
public class ProxyDemo1 {
@Test
public void demo1(){
Waiter waiter = new Waitress();
// waiter.server();
// 使用动态代理:Proxy.newProxyInstance();
/**
* ClassLoader :类加载器.
* Class[] :被增强的对象实现的所有接口
* InvocationHandler :处理类.
* /
// 第一个参数:
ClassLoader classLoader = waiter.getClass().getClassLoader();
// 第二个参数:
Class[] interfaces = waiter.getClass().getInterfaces();
// 第三次参数:
Waiter waiter2 = (Waiter)Proxy.newProxyInstance(classLoader, interfaces, new MyInvocationHandler(waiter));
waiter2.server();
// 说明现在调用代理对象的任何方法的时候,InvocationHandler中的invoke都会执行.
String s = waiter2.sayHello("张凤");
System.out.println(s);
}
}
public class MyInvocationHandler implements InvocationHandler{
private Waiter waiter;
public MyInvocationHandler(Waiter waiter){
this.waiter = waiter;
}
@Override
/**
* 方法的参数:
* * proxy :产生的代理对象.
* * method :当前正在调用的目标类的方法.
* * params :正在执行的方法中的参数.
* /
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
// System.out.println("InvocationHandler invoke 执行了...");
// System.out.println("微笑=========");
// waiter.sayHello("张凤");
// System.out.println(method.getName());
if("server".equals(method.getName())){
System.out.println("微笑==========");
Object obj = method.invoke(waiter, params);
System.out.println("白白==========");
return obj;
}else{
return method.invoke(waiter, params);
}
}
}
动态代理层次理解:
被增强的类
________|_________
| |
| |
实现类 代理对象
|
|
(构造方法:三个参数)
1.类的加载器:实现类对象.getClass().getClassLoader()
2.被增强的对象实现的所有接口:实现类对象.getClass().getInterfaces()
3.处理类:InvocationHandler接口的实现类
|
|
(InvocationHandler接口中只有一个invoke方法:需要重写)
方法中传入三个参数:
1.Object proxy:产生的代理对象.
2.Method method:当前正在调用的目标类的方法.
3.Object[] params:正在执行的方法中的参数.
注意:
1.method代表的就是实现类的里边的方法
2.通过反射调用method方法就是调用了实现类中相应的方法
3.调用method方法的前后都可以添加代码,被增强的类的对象调用方法时,就会实现invoke方法
4.创建InvocationHandler接口的实现类,通过构造方法,将要增强的类的对象传入,在赋值给他的成员变量(类型相同)
字符集编码过滤器的动态代理代码实现:
[Java] 纯文本查看 复制代码
@WebFilter(urlPatterns="/*")
public class GenericEncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
final HttpServletRequest req = (HttpServletRequest) request;
// 增强req:
HttpServletRequest myReq = (HttpServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(),
req.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断执行的方法是否是getParameter:
if("getParameter".equals(method.getName())){
// 调用的是getParameter:需要增强这个方法.
// 判断请求方式是GET还是POST:
String type = req.getMethod();
if("get".equalsIgnoreCase(type)){
String value = (String) method.invoke(req, args);
value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
return value;
}else if("post".equalsIgnoreCase(type)){
req.setCharacterEncoding("UTF-8");
}
}
return method.invoke(req, args);
}
});
chain.doFilter(myReq, response);
}
@Override
public void destroy() {
}
}
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |