javaWeb学习笔记整理(下)

Filter过滤器

**作用:**拦截请求

当用户请求某个Servlet时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继承执行用户请求的Servlet;如果Filter不“放行”,那么就不会执行用户请求的Servlet。

其实可以这样理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定。可以理解为,Filter来决定是否能调用Servlet!当执行完成Servlet的代码后,还会执行Filter后面的代码。

使用过滤器

  1. 编写一个类实现javax.servlet.Filter接口
  2. 在web.xml文件或使用注解对过滤器进行配置, 配置该过滤器拦截哪些请求的url

FilterChain 过滤器链

doFilter()方法的参数中有一个类型为FilterChain的参数,它只有一个方法:doFilter(ServletRequest,ServletResponse)

前面我们说doFilter()方法的放行,让请求流访问目标资源!但这么说不严密,其实调用该方法的意思是,“我(当前Filter)”放行了,但不代表其他人(其他过滤器)也放行。

也就是说,一个目标资源上,可能部署了多个过滤器,就好比在你去北京的路上有多个打劫的匪人(过滤器),而其中第一伙匪人放行了,但不代表第二伙匪人也放行了,所以调用FilterChain类的doFilter()方法表示的是执行下一个过滤器的doFilter()方法,或者是执行目标资源!

如果当前过滤器是最后一个过滤器,那么调用chain.doFilter()方法表示执行目标资源,果不是最后一个过滤器,那么chain.doFilter()表示执行下一个过滤器的doFilter()方法。

放行
filterChain.doFilter(servletRequest,servletResponse);

如果Filter没有显示调用上面这一行代码,表示该过滤器不放行

过滤器的执行顺序:

使用web.xml配置文件配置过滤器: 过滤器的配置文件决定过滤器执行顺序

由过滤器的<filter-mapper>顺序决定的, 谁的<filter-mapper>在前,谁先执行

在web3.0提供注解@WebFilter的配置方式:

使用注解的方式, 过滤器执行的顺序, 由过滤器的名字决定,排在前面的先执行。 当有多个过滤器时, 推荐使用web.xml配置

访问控制

有些资源,必须登录了才能访问 例如:增删改必须登录才能访问

案例 未登录时访问拦截

被拦截的url执行过滤器的doFilter方法
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
    
    
//        1.判断是否已经登录
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;
        HttpSession session = request.getSession();
        if(session.getAttribute("admin")!=null){
    
    
//            已登录,放行
            chain.doFilter(req, resp);
            return;//不执行后续方法内代码
        }
//        2.未登录,拦截,跳转到登录界面
        String requestURI = request.getRequestURI();//用户想要访问的资源
        session.setAttribute("requestPage",requestURI);
        response.sendRedirect(request.getContextPath()+"/login.jsp");
    }
注意点:
  1. ServletRequest的对象req没有request.getSession()方法,所以要将对象转换成它的子类HttpServletRequest

2.判断是否放行的依据是用户是否已经登录,所以LoginServlet处理时若登录成功要将登录用户保存到域里作为依据

3.若放行,注意方法后的代码不要执行了(使用return 或else语句)

4.如果用户未登录,拦截跳转到登录界面,这里需要注意,若用户登录成功,应该跳转到用户想要访问的资源而不是首页(不要写死登录成功后跳转的界面)

  1. 用户想要访问资源被拦截时,保存用户想要访问的资源到域里( request.getRequestURI()),登录成功后跳转到保存的这个资源
LoginServlet处理用户登录请求
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
//        1.设置编码
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html,charset=utf-8");

        String error ="";
        HttpSession session = request.getSession();
    
//        2.获取数据
        String username = request.getParameter("username");
        String psaaword = request.getParameter("password");
    
//        3.调用service
        AdminService adminService = BeanFactory.creatBean(AdminService.class);
        Admin admin = adminService.login(username, psaaword);

        //判断验证码是否正确
        String verifycode = request.getParameter("verifycode");
        String checkcode = session.getAttribute("CHECKCODE_SERVER").toString();
        if(!checkcode.equalsIgnoreCase(verifycode)){
    
     //不相等
            error="验证码输入错误";
            request.setAttribute("error",error);
            request.getRequestDispatcher("/login.jsp").forward(request,response);
            return;//验证码出错。不执行后续代码
        }

       //判断用户是否存在
        if (admin != null) {
    
    
//5.把数据保存域中, admin保存到session域
            session.setAttribute("admin",admin);

            //用户是否勾选记住密码
            String remenberPassword = request.getParameter("remenberPassword");
            if ("rem".equals(remenberPassword)) {
    
     //勾选
                //创建用户名cookie, 密码cookie (加密)
                Cookie nameCookie = new Cookie("username", username);
                Cookie passwordCookie = new Cookie("password", psaaword);
                //默认7天有效
                nameCookie.setMaxAge(7 * 24 * 60 * 60);
                passwordCookie.setMaxAge(7 * 24 * 60 * 60);
                //保存到客户端浏览器
                response.addCookie(nameCookie);
                response.addCookie(passwordCookie);
            } else {
    
    //没有勾选, 判断之前是否保存账户密码的Cookie有就删除
                Cookie[] cookies = request.getCookies();
                if (cookies != null && cookies.length > 0) {
    
    
                    for (Cookie cookie : cookies) {
    
    
                        if (cookie.getName().equals("username") || cookie.getName().equals("password")) {
    
    
                            //删除
                            cookie.setMaxAge(0);
                            response.addCookie(cookie);
                        }
                    }
                }

            }
            //  登录成功 重定向
            //从session获取到想访问的资源
            Object requestPage = session.getAttribute("requestPage");
            if(requestPage == null){
    
    
                response.sendRedirect(request.getContextPath()+"/index.jsp");
            }else{
    
    
                response.sendRedirect(request.getContextPath()+requestPage);
                //把session域中requestPage属性删除
                session.removeAttribute("requestPage");
            }
        }else if(admin==null){
    
    //登录失败
            //5.把数据保存域中
            error = "用户名或者密码错误";
            request.setAttribute("error",error);
            //6.页面跳转 转发: 把数据存在request域
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }

    }
注意点:

用户如果是从被拦截后的登录页面登录成功的,那么登录成功之后记得要把session里的requestURI删除掉,否则这个session会在本次会话一直存在,有可能会导致下次登录时还是跳转到该页面

WEB-INF下的文件不能直接访问,只能通过转发访问,所以被拦截的资源文件夹可以放在WEB-INF中

四种拦截方式

REQUEST、FORWARD、INCLUDE、ERROR。

可以在<filter-mapping>中添加0~n个<dispatcher>子元素,来说明当前访问的拦截方式。

文件上传

这里的文件上传是小文件上传

大文件上传需要编写TCP进行大文件上传

实现:客户端把一个本地文件(图片,视频,音频,文本文件…) 上传到服务器, 保存在服务器中

文件上传对前端的要求

  1. 必须使用表单,而不能是超链接;
  2. 表单的method必须是POST,而不能是GET;
  3. 表单的enctype必须是multipart/form-data;
  4. 使用表单元素: `
<form action="${pageContext.request.contextPath }/FileUploadServlet" method="post" enctype="multipart/form-data">
    	用户名:<input type="text" name="username"/><br/>
    	文件1:<input type="file" name="file1"/><br/>
    	文件2:<input type="file" name="file2"/><br/>
    	<input type="submit" value="提交"/>
    </form>

文件上传对后端的要求

当提交的表单是文件上传表单时,那么对Servlet也是有要求的。

首先我们要肯定一点,文件上传表单的数据也是被封装到request对象中的。

  1. form表单 enctype的值为"multipart/form-data" 时,request.getParamter()这个方法失效
  2. 可以通过请求对象的ServletInputStream得到数据, 也可以借助第三方的jar包,apache提供的 commons-fileupload.jar

request.getParameter(String)方法获取指定的表单字段字符内容,但文件上传表单已经不在是字符内容,而是字节内容,所以失效。

这时可以使用request的getInputStream()方法获取ServletInputStream对象,它是InputStream的子类,这个ServletInputStream对象对应整个表单的正文部分(从第一个分隔线开始,到最后),这说明我们需要的解析流中的数据。当然解析它是很麻烦的一件事情,而Apache已经帮我们提供了解析它的工具**:commons-fileupload。**

使用Commons-fileupload步骤

  1. 导入依赖
  2. 创建DiskFileItemFactory工厂类, FileItem: 对应表单的表单项(input,select,teaxarea)
  3. 创建一个Request对象解析器 ServletFileUpload
  4. 解析Request对象 ServletFileUpload的 List<FileItem> parseRequest(request)
  5. 遍历第4步的 得到List<FileItem> 得到一个一个FileItem,根据FileItem类型(普通表单项,非普通表单项(文件表单))进行处理

文件上传的细节

客户端上传的文件保存在服务器的硬盘上, 前端默认无法访问得到,

如何让客户端能够访问到上传到服务器的文件?,

Tomcat提供虚拟路径,

给服务器硬盘的某个路径映射一个访问的url, 当客户端访问这个url时, 间接的去访问服务器上对应硬盘的路径下的资源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4HpZ9Cc3-1667978787131)(D:\飞思实训三\6.JavaWeb\笔记\5_Filter和文件上传\assets\image-20221025160917060.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-23V1hNgI-1667978787132)(D:\飞思实训三\6.JavaWeb\笔记\5_Filter和文件上传\assets\image-20221025160938768.png)]

选择硬盘地址

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s6zX7K3k-1667978787132)(D:\飞思实训三\6.JavaWeb\笔记\5_Filter和文件上传\assets\image-20221025161105316.png)]

设置url

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v9uWdn4x-1667978787134)(D:\飞思实训三\6.JavaWeb\笔记\5_Filter和文件上传\assets\image-20221025161236835.png)]

fileupload概述

fileupload是由apache的commons组件提供的上传组件。它最主要的工作就是帮我们解析request.getInputStream()。

fileupload组件需要的JAR包有:

commons-fileupload.jar,核心包;

commons-io.jar,依赖包

fileupload简单应用

fileupload的核心类有:DiskFileItemFactory、ServletFileUpload、FileItem。

使用fileupload组件的步骤如下:

  1. 创建工厂类DiskFileItemFactory对象:DiskFileItemFactory factory = new DiskFileItemFactory()
  2. 使用工厂创建解析器对象:ServletFileUpload fileUpload = new ServletFileUpload(factory)
  3. 使用解析器来解析request对象:List list = fileUpload.parseRequest(request)

隆重介绍FileItem类,它才是我们最终要的结果。一个FileItem对象对应一个表单项(表单字段)。一个表单中存在文件字段和普通字段,可以使用FileItem类的isFormField()方法来判断表单字段是否为普通字段,如果不是普通字段,那么就是文件字段了。

  • String getName():获取文件字段的文件名称;
  • String getString():获取字段的内容,如果是文件字段,那么获取的是文件内容,当然上传的文件必须是文本文件;
  • String getFieldName():获取字段名称,例如:,返回的是username;
  • String getContentType():获取上传的文件的类型,例如:text/plain。
  • int getSize():获取上传文件的大小;
  • boolean isFormField():判断当前表单字段是否为普通文本字段,如果返回false,说明是文件字段;
  • InputStream getInputStream():获取上传文件对应的输入流;
  • void write(File):把上传的文件保存到指定文件中。

案例 上传文件

处理文件上传UploadServlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
    
        //借助于 commons-fileupload
        //1.创建DiskFileItemFactory对象
        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();

        //2.创建一个解析Request对象解析器 ServletFileUpload
        ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);

        try {
    
    
            //3.解析Request对象
            List<FileItem> fileItems = servletFileUpload.parseRequest(request);
            //4.遍历fileItems
            for (FileItem fileItem : fileItems) {
    
    
                //5.判断是否为普通表单
                if (fileItem.isFormField()) {
    
    //true 普通表单
                    String fieldName = fileItem.getFieldName();//获取name值
                    String value = fileItem.getString("UTF-8");//获取表单的value
                    System.out.println(fieldName + ":" + value);
                } else {
    
    //文件表单
                    //上传的文件保存到服务器的硬盘上
                    String savePath = "D:/upload/";
                    //得到上传的文件名 getName() 
                    String uploadFilename = fileItem.getName();
                    // 创建一个文件名  文件名称 + 后缀名(上传文件的后缀名)
                    String saveFile = FileUploadUtil.randomFileNameWithUUID() + FileUploadUtil.getFileSuffix(uploadFilename);
                    //保存 FileItem的write(File file)
                    fileItem.write(new File(savePath, saveFile));
                }
            }
        }catch (FileUploadException e) {
    
    
            e.printStackTrace();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
注意点:

1.服务器中保存的文件名应该是唯一的,不能以用户上传的文件名来保存到服务器中

2.文件名唯一的处理方法(可以封装工具类)

使用时间戳拼接其他(例如用户名等等)

使用java内置的UUID获取随机生成的32位16进制字符串

3.保存文件的方法 FileItem.write(File file)

4.保存到服务器时别忘记拼接文件的后缀名,String uploadFilename = fileItem.getName(); (工具类封装方法截取后缀名)

工具类FileUploadUtil
public class FileUploadUtil {
    
    
    /**
     * 得到文件名的后缀
     * @param fileName
     * @return
     */
    public static String getFileSuffix(String fileName){
    
    
        if(fileName==null||fileName.isEmpty()){
    
    
            throw new RuntimeException("找不到文件,filename:"+fileName);
        }
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 使用UUID生成文件名
     */
    public static String randomFileNameWithUUID(){
    
    
        return UUID.randomUUID().toString().replaceAll("-","");
    }

    /**
     * 基于时间戳生成文件名
     */
    public static String randomFileNameWithTime(){
    
    
        return System.currentTimeMillis()+"";
    }

    /**
     * 基于时间戳 + UUID生成文件名
     * @return
     */
    public static String randomFilenameWithUUIDandTime(){
    
    
        return System.currentTimeMillis()+randomFileNameWithUUID();
    }
}

ajax

异步的JavaScript和XML

AJax的两大特点:

  • 异步通信
  • 局部刷新

JSON

JSON语法格式:
  1. 数据以key/value对存储, key:value
  2. 数据与数据之间使用逗号分割: k1:v1,k2:v2
  3. 使用 {} 表示一个对象 {"id":1,"name":"张三"}
  4. 使用[] 表示一个数组 {"id":1,"name":"张三","loves":["read","music"]}

stus:[{"id":1,"name":"张三"},{"id":2,"name":"李四",sex:null}]

注意:

  1. key一定使用双引号引起
  2. 如果value是字符串,一定使用双引号引起
JSON值:
  • 数字(整数或浮点数)
  • 字符串(在双引号中)
  • 逻辑值(true 或 false)
  • 数组(在方括号中 []
  • 对象(在花括号中 {}
  • null

ES5语法中 JSON类

JSON.parse(json字符串): 把JSON字符串转换为js对象

JSON.stringify(js对象): 把js对象转换为JSON格式字符串

JQuery中:

$.parseJSON(json字符串): 把json字符串转换为js对象, 该方法在jquery3.0 以后的版本删除

java对象与json的转换

借助第三方的jar: fastJson, jackson, json-lib…

课件: fastJson: 阿里巴巴的

核心类: JSON

核心方法:

把json字符串转换为java对象: parseObject()

把对象数组形式json字符串转换为java的List集合: parseArray()

把java对象转换为json字符串: toJSONString()

@JSONField注解
Student类 设置不可序列化及JSON的日期格式(使用fastjson jar包)
@JSONField(serialize=false)
private Integer age;
//format: 字符串转换格式
@JSONField(format="yyyy-MM-dd")
private Date birthday;  //在实体类中, Date类一定是java.util.Date

jackson, json-lib…

课件: fastJson: 阿里巴巴的

核心类: JSON

核心方法:

把json字符串转换为java对象: parseObject()

把对象数组形式json字符串转换为java的List集合: parseArray()

把java对象转换为json字符串: toJSONString()

@JSONField注解
Student类 设置不可序列化及JSON的日期格式(使用fastjson jar包)
@JSONField(serialize=false)
private Integer age;
//format: 字符串转换格式
@JSONField(format="yyyy-MM-dd")
private Date birthday;  //在实体类中, Date类一定是java.util.Date

猜你喜欢

转载自blog.csdn.net/m0_48895748/article/details/127770775
今日推荐