javaweb的三大组件:servlet , Filter,Listener
Filter(过滤器)
- 概念:
生活中的过滤器:净水器,空气净化器,土匪、
web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
过滤器的作用:
一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤…
Filter快速入门
步骤:
- 定义一个类实现Filter接口,注意是 javax.servlet下面的Filter接口
- 复写方法,
配置拦截路径
- web.xml
2. 在类的上面添加注解 @WebFilter(“/“) // / 表示访问所有资源之前都进行filter的过滤
- web.xml
注解方法配置过滤器的代码
package filter;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.xml.ws.WebFault;import java.io.IOException;@WebFilter("/*") // /* 表示访问所有资源之前都进行filter的过滤public class filterdemo1 implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println("filter 执行了 ... ");//你要放行吗//放行filterChain.doFilter(servletRequest,servletResponse);}@Overridepublic void destroy() {}}
web.xml配置过滤器的代码
<?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"><!-- 进行filter的配置--><filter><!-- 给filter起一个别名--><filter-name>demo1</filter-name><!-- filter文件的路径 --><filter-class>filter.filterdemo1</filter-class></filter><filter-mapping><filter-name>demo1</filter-name><!-- url-pattern标签里面设置的是filter的拦截路径 --><url-pattern>/*</url-pattern></filter-mapping></web-app>
过滤器的详解
web.xml配置(如上代码)
过滤器的执行流程
先通过过滤器去访问资源,然后再回到过滤器,执行放行代码下面的部分
过滤器的生命周期方法
- init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
2. doFilter:每一次请求被拦截资源时,会执行。执行多次
3. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源过滤器的配置详解
拦截路径的配置
- 具体资源路径: /index.jsp 只有访问index.jsp资源时,过滤器才会被执行
2. 拦截目录: /user/ 访问/user下的所有资源时,过滤器都会被执行
/user/ 这个user指的并不是一个问价夹,而是一个访问的虚拟路径,就算servlet在不同的文件夹下面,只要他们的虚拟路径都在/user下面就都会被过滤
更加准确的说就是只要你在浏览器的地址栏里面输入的是/user/xxx 后面的数据就都会被过滤
- 后缀名拦截: .jsp 访问所有后缀名为jsp资源时,过滤器都会被执行
4. 拦截所有资源:/ 访问所有资源时,过滤器都会被执行
根据访问资源的方式进行拦截
- 注解配置:通过访问资源的方式拦截
设置dispatcherTypes属性
1. REQUEST:默认值。浏览器直接请求资源
2. FORWARD:转发访问资源
3. INCLUDE:包含访问资源
4. ERROR:错误跳转资源
5. ASYNC:异步访问资源 sync 之指的就是sychonize(同步)
Filter的注解展示
//@WebFilter(value = "/index.jsp" , dispatcherTypes = DispatcherType.REQUEST)//默认的情况下其实就是dispatcherTypes =DispatcherType.REQUEST//意思就是浏览器直接访问index。jsp文件的时候会被过滤,但是你在servlet里面使用req.getRequestDispatcher().forword()时候不会别过滤//但是我发现在使用 resp.sendRedirect("/day19/index.jsp");访问index.jsp的时候还是会被过滤器给过滤的//@WebFilter(value = "/index.jsp" , dispatcherTypes = DispatcherType.FORWARD)//这个只有在转发的时候才会被过滤,也就是使用req.getRequestDispatcher().forword()的时候才会被过滤//现在我想在直接请求和转发的时候都进行过滤,就是在dispatcherTypes参数里面写上数组就可以了,dispatcherTypes的参数其实就是一个数组@WebFilter(value = "/index.jsp" , dispatcherTypes = {DispatcherType.FORWARD,DispatcherType.REQUEST})//直接访问,forword,redirect的时候都会被过滤public class demo5 implements Filter {
- 通过web.xml文件进行配置,主要就是,
标签里面的值 <!-- 进行filter的配置--><filter><!-- 给filter起一个别名--><filter-name>demo1</filter-name><!-- filter文件的路径 --><filter-class>filter.filterdemo1</filter-class></filter><filter-mapping><filter-name>demo1</filter-name><!-- url-pattern标签里面设置的是filter的拦截路径 --><url-pattern>/*</url-pattern><!-- 通过访问的方式进行过滤 也是有5种取值 , forword request error async include--><dispatcher>FORWARD</dispatcher><dispatcher>REQUEST</dispatcher></filter-mapping>
过滤器链(多个过滤器)
执行顺序:如果有两个过滤器:过滤器1和过滤器2
1. 过滤器1
2. 过滤器2
3. 资源执行
4. 过滤器2
5. 过滤器1过滤器先后顺序问题:
1. 注解配置:按照类名的字符串比较规则比较(就是字典顺序),值小的先执行
* 如: AFilter 和 BFilter,AFilter就先执行了。
2. web.xml配置:谁定义在上边,谁先执行
案例一:验证登录
- 案例1_登录验证
* 需求:
1. 访问day17_case案例的资源。验证其是否登录
2. 如果登录了,则直接放行。
3. 如果没有登录,则跳转到登录页面,提示”您尚未登录,请先登录”。
登录控制的原理
注意
我们过滤器过滤的文件是所有文件(含有验证码,所有servlet,样式,登录界面也会拦截 等等),所以我们要排除和登录操作有关的文件(比如登录的界面,登录界面里面的样式,验证码等等。。),不然你就真的没有办法登录了。
Filter实现的代码
需要注意的就是我们检查到用户已经登录之后要做的一件事就是放行,而不是在过滤器里面进行跳转
package web.filter;import com.sun.deploy.net.HttpRequest;import domain.User;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import java.io.IOException;@WebFilter("/*")public class LoginFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {//我先过的资源的请求路径,看他是不是想到login。jsp或者loginservlet里面去 使用HttpServletrequest里面的getRequestUri//强转 将ServletRequest 转为HttpSevletRquestHttpServletRequest request = (HttpServletRequest) servletRequest;String requestURI = request.getRequestURI();//判断是否是和登录相关的资源 这里涉及到的资源其实是很多的,比如css fonts js 有可能还包含有图片的if (requestURI.contains("/login.jsp") || requestURI.contains("/loginServlet") || requestURI.contains("/css/")|| requestURI.contains("/fonts/") || requestURI.contains("/js/") || requestURI.contains("/checkCodeServlet")){//我就是想登录就放行filterChain.doFilter(servletRequest,servletResponse);}else {//想访问别的资源的话就看看你有没有登陆 前面我们登录成功的时候会将用户的信息放到loginuser里面去//判断loginuser里面有没有数据User loginuser = (User) request.getSession().getAttribute("loginuser");// System.out.println("filter 收到user : " + loginuser);if (loginuser == null){//为空说明你还没有登陆 跳转到登录界面//放入一些提示信息request.setAttribute("loginMsg" ,"您还没有登录,请先登录");request.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);}else{//不是空的话说明你已经登陆过了,开始跳转list.jsp页面// request.getRequestDispatcher("/findUserByPageServlet").forward(servletRequest,servletResponse);//放行filterChain.doFilter(servletRequest,servletResponse);}}}@Overridepublic void destroy() {}}
案例二:过滤敏感词汇
实现思路图解
需要注意的是这个Filter里面的request对象,和别的地方传入的request对象其实同一个对象,
我们需要做的就是得到这个对象里面的数据(使用request.getParameter()方法),然后将request里面的值进行修改。但是但是我们修改了值以后怎样在将新的一个数据放到request里面是一个大的问题。???
将新的数据放到request里面,就是要将request进行增强。
- 分析:
1. 对request对象进行增强。增强获取参数相关方法
2. 放行。传递代理对象
增强对象的功能:
设计模式:一些通用的解决固定问题的方式
1. 装饰模式
2. 代理模式
概念:
1. 真实对象:被代理的对象
2. 代理对象:
3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
实现方式:
1. 静态代理:有一个类文件描述代理模式
2. 动态代理:在内存中形成代理类
实现步骤:
1. 代理对象和真实对象实现相同的接口
2. 代理对象 = Proxy.newProxyInstance();
3. 使用代理对象调用方法。
4. 增强方法增强方式:
1. 增强参数列表
2. 增强返回值类型
3. 增强方法体执行逻辑
一个增强对象的小案例
我们可以实现调用方法以后将方法里面的参数的数值变为原来的85%
真实的类(被代理的类)Lenovo
package proxy;public class Lenovo implements SaleComputer{//这个就是一个真实的类:就是被代理的类@Overridepublic String sale(double money) {System.out.println("花了"+money+"元买了一台联想电脑");return "lenovo computer ..." ;}@Overridepublic void show() {System.out.println("show......");}}
接口
package proxy;public interface SaleComputer {String sale(double money);void show();}
真实类和代理类都用的是同一个接口
package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyTest {public static void main(String[] args) {//创建真实的对象 lenovoLenovo lenovo = new Lenovo();//使用真实对象调用方法// String sale = l.sale(8009);// System.out.println(sale);//使用动态带代理增强lenovo对象 使用Proxy.newProxyInstance方法 里面有三个参数/*** 三个参数* 1.类加载器: 真实对象.getClass().getClassLoader()* 2.接口数组: 真实对象.getClass().getInterfaces()* 3.处理器 : 其实是一个匿名内部类new InvocationHandler() {}* 回忆一下匿名内部类,就是我们直接写一个匿名的类来实现接口里面的方法** 最终返回的是一个代理对象* 代理类和实现类 实现的是相同的接口 我们就把这个返回的代理类强转为接口类型*/SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {/*** 实现增强的真实代码 代理对象调用所有的方法的时候都会执行invoke()里的方法* @param proxy 代理对象* @param method 真实对象调用的方法,在这里封装成为了一个method对象* @param args 真实对象调用法的时候传递的参数*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// System.out.println("invoke ....");// System.out.println(method.getName());// System.out.println(args[0]);//代理对象调用方法,实际上还是要依靠真实对象来实现的//Object returnValue = method.invoke(lenovo, args);//使用真实对象lenovo调用method对应的方法,方法的参数是args数组中的值,方法的返回值就是invoke//我们来实现方法的增强//改变sale方法里面的参数值(double) 价格变为原来的85%//判断是不是sale方法,是的话进行增强if (method.getName().equals("sale")){ //如果调用的是sale方法//1.增强参数//拿到里面的参数列表args,其实sale只有一个参数 ,将参数值变为原来的85%double money =(double) args[0]*0.85;//将新的参数设置给方法Object returnValue = method.invoke(lenovo, money);//2.增强返回值return returnValue+"_送鼠标" ;}else {//如果是别的方法不变Object invoke = method.invoke(lenovo, args);return invoke;}// return returnValue;}});//代理类调用方法String sale = proxy_lenovo.sale(8000);System.out.println(sale);System.out.println("---------------");proxy_lenovo.show();}}
敏感词汇过滤
在day18_testAll 进行铭感词汇过滤
先写一个得到request方法的servlet
package web.servlet;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 java.io.IOException;@WebServlet("/testSensitiveFilter")public class testSensitiveFilter extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String name = req.getParameter("name");String msg = req.getParameter("msg");System.out.println(name+"----"+msg);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req,resp);}}
敏感词汇过滤器。注意增强方法 以后一定要记得放行
里面还包含了读取敏感词汇文件的代码,在filter的init里面加载敏感词汇文件
package web.filter;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.swing.*;import java.io.*;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.List;@WebFilter("/*") //注意最后一定要放行public class SensitiveWordsFilter implements Filter {private List<String> list = new ArrayList<>(); // 存放敏感词汇@Overridepublic void init(FilterConfig filterConfig) throws ServletException {/*** 回忆一下之前的IO知识 字节流是FileInputStream* InputStreamReader将字节流转化为字符流 ,在这里可以设置字符流的编码格式* BufferReader可以再将字符流变得更加高效*/try {//读取敏感词汇的文件String realPath = filterConfig.getServletContext().getRealPath("/WEB-INF/classes/sensitivewords.txt");//读取文件 使用高效的bufferreader读取文件的时候是没有办法设置读取的文件编码的 要使用InputStreamreader才可以设置编码格式的// 读取文件的时候我们一步一步的进行封装 ,//1.得到字节输入流FileInputStream fis = new FileInputStream(realPath);//2.字符流转化为字节流并设置编码格式InputStreamReader isr = new InputStreamReader(fis,"utf-8");//3.将字节流转化为更高效的字符缓存流BufferedReader br = new BufferedReader(isr);//一次读取一行String filedata = null;while ((filedata = br.readLine()) != null){//添加到集合里面去list.add(filedata);}//释放资源br.close();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}//输出一下文件里面的数据//System.out.println(list);}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {//我们在这里对request的getParameter()方法进行增强 --动态代理//我们其实是对 ServletRequest 的getParameter()方法进行代理得 所以返回值就是ServletRequestServletRequest prox_req = (ServletRequest) Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//在这里对getParameter()方法进行增强if (method.getName().equals("getParameter")){//在这里进行返回值的增强//得到返回值 其实就是得到getparameter里面的值String value = (String) method.invoke(servletRequest,args);//这句的意思就是调用servletRequest的method方法(这里值得就是getParameter());if (value != null){//判断是否含有敏感词汇for (String sensitive : list) {if (value.contains(sensitive)){//将value里面的敏感词替换为***value = value.replaceAll(sensitive,"***");}}}return value;}/*上面仅仅是对getParameter方法进行了一增强,我们后期还是要对getparametermap 。。等方法进行增强,因为这些方法也可以获得参数的**///如果不是getparamemter()方法就按照原来的方法执行return method.invoke(servletRequest,args);//这里的返回值就是最终调用方法的返回值}});//2.放行 注意放行的时候是吧我的代理对象给传递过去了 以后他们肯定会使用我的代理对象调用getParameter方法,这样我的增强返回值就可以生效了filterChain.doFilter(prox_req,servletResponse);}@Overridepublic void destroy() {}}
测试的时候可以直接访问服务器的时候带上参数
输出的结果就是
Listener:监听器
* 概念:web的三大组件之一。Listener ,Filter,servlet在创建之后都需要进行配置<br /> * 事件监听机制<br /> * 事件 :一件事情<br /> * 事件源 :事件发生的地方<br /> * 监听器 :一个对象<br /> * 注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码* ServletContextListener:监听ServletContext对象的创建和销毁<br /> * 方法:<br /> * void contextDestroyed(ServletContextEvent sce) :ServletContext对象被销毁之前会调用该方法<br /> * void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法
创建监听器的步骤:
1. 定义一个类,实现ServletContextListener接口
2. 复写方法
3. 配置
1. web.xml
web.xml配置的代码
<!-- 对监听器进行配置--><listener><listener-class>listener.listenerdemo</listener-class></listener><!-- 指定初始化参数 使用键值对的方式存储的 我这里放一个文件的存储路径不管是注解配置listener还是在web。xml文件里面进行配置加载文件的时候都要用到下面的参数使用监听器加载文件的时候才需要这些参数--><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/classes/applicationConfig.xml</param-value></context-param></web-app>
* 指定初始化参数<context-param><br /> 2. 注解:<br /> * @WebListener
3.监听器的代码
package listener;import javax.servlet.ServletContext;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;import javax.servlet.annotation.WebListener;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.InputStream;import java.io.InputStreamReader;//我们先去web.xml文件里面进行配置 也可使用注解进行配置/*** 对监听器进行配置 其实就是告诉服务器我listener.listenerdemo是一个监听器* <listener>* <listener-class>listener.listenerdemo</listener-class>* </listener>*///web,xml文件里面的三行代码其实就是等于 注解的一行代码@WebListener@WebListenerpublic class listenerdemo implements ServletContextListener {/*** 在服务器启动的时候自动开始执行里面的代码* @param servletContextEvent*/@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {System.out.println("listener 执行了");//1 加载servletcontext对象ServletContext servletContext =servletContextEvent.getServletContext();//2 通过servletcontext对象读web,xml文件String filePath = servletContext.getInitParameter("contextConfigLocation");//System.out.println("filepath:"+filePath); //filepath:/WEB-INF/classes/applicationConfig.xml//3.获取真实路径String realPath = servletContext.getRealPath(filePath);//System.out.println("realpath:"+realPath);//D:\myApp\IDEAProject\day19_filter\out\artifacts\day19_filter_war_exploded\WEB-INF\classes\applicationConfig.xmltry {//这个方法在服务器创建的时候开始被执行 我们就在这里进行配置资源的加载FileInputStream is = new FileInputStream(realPath); //这里写的要是真实的路径 就在电脑里面的路径//当然这里的文件的路径我们要动态进行获取不能写死,我们要把这个文件的路径写在web.xml文件里面System.out.println(is);} catch (FileNotFoundException e) {e.printStackTrace();}}/*** 服务器正常关闭的时候执行下面的代码* @param servletContextEvent*/@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {System.out.println("listener 结束了");}}
//我们在使用监听器的时候加载了一个文件,
加载文件的注意的事项
我们在过滤器里面和监听器里面都使用过文件的加载,
首先我们需要明的一点是;我使用FileInputStream , InputStreamReader的时候里面的参数其实是文件在电脑里面的一个绝对路径
我们要想得到文件的绝对路径就是先得到文件在服务器(可能要用到/WEB-INF/classes )里面的相对路径。通过getRealPath来得到文件的一个真是路径给FileInputStream (), InputStreamReader()方法使用
根据下面三个web组件得到文件真实路径的方法 ,都是使用
ServletContext的getRealpath(/WEB-INF/classes相对路径)方法来得到真实路径的,而且得到serbletcontext对象都是通过类里面的第一个方法的第一个参数来得到的
加载文件时候的乱码问题:
可以参考下面Servlet加载文件的代码,最主要的就是使用InputStreamReader可以设置字符的编码格式
//开始加载数据FileInputStream fis = new FileInputStream(realPath);//包装为字符流 并设置编码格式InputStreamReader isr = new InputStreamReader(fis,"utf-8");//封装为高效字符流BufferedReader br = new BufferedReader(isr);
Filter加载文件资源
注意是谁调用的getRealpath
可以看到是filterConfig.getServletContext().getRealPath
String realPath = filterConfig.getServletContext().getRealPath(“/WEB-INF/classes/sensitivewords.txt”);
public class SensitiveWordsFilter implements Filter {private List<String> list = new ArrayList<>(); // 存放敏感词汇@Overridepublic void init(FilterConfig filterConfig) throws ServletException {/*** 回忆一下之前的IO知识 字节流是FileInputStream* InputStreamReader将字节流转化为字符流 ,在这里可以设置字符流的编码格式* BufferReader可以再将字符流变得更加高效*/try {//读取敏感词汇的文件String realPath = filterConfig.getServletContext().getRealPath("/WEB-INF/classes/sensitivewords.txt");//读取文件 使用高效的bufferreader读取文件的时候是没有办法设置读取的文件编码的 要使用InputStreamreader才可以设置编码格式的// 读取文件的时候我们一步一步的进行封装 ,//1.得到字节输入流FileInputStream fis = new FileInputStream(realPath);
Listener加载文件
看看listenter是用谁加载的文件资源
ServletContext servletContext =servletContextEvent.getServletContext();
String filePath = servletContext.getInitParameter(“contextConfigLocation”);
String realPath = servletContext.getRealPath(filePath);
@WebListenerpublic class listenerdemo implements ServletContextListener {/*** 在服务器启动的时候自动开始执行里面的代码* @param servletContextEvent*/@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {System.out.println("listener 执行了");//1 加载servletcontext对象ServletContext servletContext =servletContextEvent.getServletContext();//2 通过servletcontext对象读web,xml文件String filePath = servletContext.getInitParameter("contextConfigLocation");//System.out.println("filepath:"+filePath); //filepath:/WEB-INF/classes/applicationConfig.xml//3.获取真实路径String realPath = servletContext.getRealPath(filePath);//System.out.println("realpath:"+realPath);//D:\myApp\IDEAProject\day19_filter\out\artifacts\day19_filter_war_exploded\WEB-INF\classes\applicationConfig.xmltry {//这个方法在服务器创建的时候开始被执行 我们就在这里进行配置资源的加载FileInputStream is = new FileInputStream(realPath); //这里写的要是真实的路径 就在电脑里面的路径//当然这里的文件的路径我们要动态进行获取不能写死,我们要把这个文件的路径写在web.xml文件里面System.out.println(is);
servlet加载文件
看看servlet是怎么得到文件的真实路径的
String realPath = req.getServletContext().getRealPath(“/WEB-INF/classes/words.txt”);
package servlet;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 java.io.*;import java.util.ArrayList;import java.util.List;@WebServlet("/loadfileservlet")public class loadfileservlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//访问这个servlet的时候开始加载words。txt文件、List<String> list = new ArrayList<>();String realPath = req.getServletContext().getRealPath("/WEB-INF/classes/words.txt");System.out.println(realPath);//开始加载数据FileInputStream fis = new FileInputStream(realPath);//包装为字符流 并设置编码格式InputStreamReader isr = new InputStreamReader(fis,"utf-8");//封装为高效字符流BufferedReader br = new BufferedReader(isr);//直接读取文件柜出现乱码//BufferedReader bf = new BufferedReader(new FileReader(realPath));String words = null;while ((words = br.readLine()) != null){list.add(words);}System.out.println(list);//System.out.println(fis);}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req,resp);}}
/
