Servlet

作者: 帅哥_刷哥 | 来源:发表于2017-09-21 20:18 被阅读36次

    Servlet介绍

    概述
        Servlet是运行在服务器端的Java应用程序
        servlet程序开发动态资源的技术
        Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,
        用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容。
    作用:
        用于接收和处理http请求(接收和响应请求)
    最核心的方法
        void service(ServletRequest req,ServletResponse res) 
        ServletRequest req 代表请求对象,包含请求的所有内容,用于获取请求数据
        ServletResponse res 代表响应对象,包含响应的所有内容,用于修改响应数据
    

    Servlet开发步骤

    1)java类,继承HttpServlet类
        覆盖doGet和doPost方法
    2)在web应用web.xml中配置servlet
    3)请求Servlet
    

    创建Servlet

    //第一种方式 继承 GenericServlet
        import java.io.IOException;
        import javax.servlet.GenericServlet;
        import javax.servlet.ServletException;
        import javax.servlet.ServletRequest;
        import javax.servlet.ServletResponse;
        public class OneServlet extends GenericServlet {
            private static final long serialVersionUID = -2949013647446695209L;
            @Override
            public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
            }
        }
    //第二种方式 继承 HttpServlet 
        //继承自GenericServlet类,是在其基础上扩展了Http协议的Servlet
        //会先调用service方法,然后根据请求方式来进行调用doGet/doPost
        import java.io.IOException;
        import javax.servlet.ServletException;
        import javax.servlet.http.HttpServlet;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        public class OneServlet extends HttpServlet {
            private static final long serialVersionUID = -4435501112176421548L;
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                this.doPost(req, resp);
            }
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                super.doPost(req, resp);
            }
        }
    

    配置Servlet

    在web.xml中配置
        <servlet>
            <!-- 名称要唯一 -->
            <servlet-name>one</servlet-name>
            <!-- 全路径 -->
            <servlet-class>com.shuai.action.OneServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <!-- 要与上边的名称一致 -->
            <servlet-name>one</servlet-name>
            <!-- 访问Servlet的URL,相对于Web应用的路径 -->
            <url-pattern>/one</url-pattern>
        </servlet-mapping>
    

    配置Servlet中设置初始化值

    <servlet>
        <servlet-name>one</servlet-name>
        <servlet-class>com.shuai.action.OneServlet</servlet-class>
        <!-- 设置初始化值 -->
        <init-param>
            <param-name>initParam</param-name>
            <param-value>paramtest</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>one</servlet-name>
        <url-pattern>/one</url-pattern>
    </servlet-mapping>
    @Override
    public void init(ServletConfig config) throws ServletException {
        //这个super一定不要删掉
        super.init(config);
        //通过ServletConfig对象读取初始化参数
        String initParameter = config.getInitParameter("initParam");
        System.out.println(initParameter);
        //获得所有参数的key
        Enumeration<String> enumeration = config.getInitParameterNames();
    }
    有参的init 与 无参init
        有参init:生命周期方法,必定会被服务器调用。(内部默认会调用无参的init方法)
        无参init:提供给开发者进行初始化工作的方法。
    

    Servlet生命周期

    实例化 - Servlet 容器创建 Servlet 的实例
    初始化 - 容器调用 init() 方法
    请求处理 - 如果请求 Servlet,则容器调用 service() 方法
    服务终止/重新部署 - 销毁实例之前调用 destroy() 方法,通过stop server看
    

    Servlet线程安全问题

    Servlet 在服务器中是单实例多线程的。
        每次都会在Service方法中新建一个子线程来处理请求:new ThreadServlet()
        引起并发问题的原因:在Servlet中使用了成员变量(多个线程共享的数据)。
        测试:
            可以通过在Servlet中输出一个count值,然后线程睡眠,最后count++。
            用两个浏览器同时去访问。会发现最后输出的结果是一样的。
        解决多并发,用同步
            在doGet方法中
                synchronized (OneServlet.class) {
                    //业务代码
                }
        建议:
            尽量不要在Servlet中使用成员变量
            如果使用了成员变量,那么就需要使用synchronized进行同步代码,而且尽量缩小同步的范围
    

    Servlet的一些细节

    改变Servlet的创建时机
        <servlet>
            <servlet-name>one</servlet-name>
            <servlet-class>com.shuai.action.ThreeServlet</servlet-class>
            <!-- 在项目部署启动的时候,默认创建Servlet,数值越大优先级越低 -->
            <load-on-startup>1</load-on-startup>
        </servlet>
    路径映射规则
                    url-pattern    页面访问
        精确映射       /one           /one   
                       /test/one      /test/one
    
        模糊映射       /*             /任意路径
                       /test/*        /test/任意路径
                       *.后缀         任意路径.后缀
        注意:
            url-pattern要么以/或者*开头
            当前有多个url-pattern,优先级问题
                后缀名结尾的url-pattern优先级最低
                哪个更加精确哪个优先
    

    ServletConfig对象

    概述
        Servlet配置对象
    作用
        用于读取servlet参数
    如何得到ServletConfig对象
        通过有参的init方法获得
        通过getServletConfig()获得
    

    ServletContext对象

    概述
        ServletContext是servlet的上下文对象。
        代表当前web应用。
        一个web有且只有一个ServletContext对象。
    获取ServletContext对象
        ServletContext servletContext = getServletConfig().getServletContext();
        ServletContext servletContext = getServletContext();
    作用
        作为全局的域对象使用
        读取全局的配置参数
        转发web应用内的资源
        读取web应用内的文件
    具体使用
        设置全局属性参数
            ServletContext servletContext = getServletContext();
            servletContext.setAttribute("name", "zhangsan");
            String str = (String)servletContext.getAttribute("name");
        读取全局参数
            <!-- 全局参数 -->
            <context-param>
                <param-name>onep</param-name>
                <param-value>onep</param-value>
            </context-param>
            <context-param>
                <param-name>twop</param-name>
                <param-value>twop</param-value>
            </context-param>
            ServletContext servletContext = getServletContext();
            String onep = servletContext.getInitParameter("onep");
            String twop = servletContext.getInitParameter("twop");
        转发
            ServletContext servletContext = getServletContext();
            //转发内部资源
            RequestDispatcher dispatcher = servletContext.getRequestDispatcher("info.jsp");
            dispatcher.forward(req, res);
        读取web应用内的文件
            ServletContext servletContext = getServletContext();
            //获取一个文件的绝对路径 - 获取的项目根目录
            //要以/开头
            String realPath = servletContext.getRealPath("/");
            System.out.println(realPath);
            //读取一个文件,并且返回一个文件流
            InputStream inputStream = servletContext.getResourceAsStream("/路径");
    

    HttpServletResponse对象

    response对象
        表示响应对象,包含所有的响应数据。使用response对象可以修改响应数据。
    响应格式
        响应行
            http版本
            状态码 setStatus(sc)方法
            描述
        响应头
            键值对 
                setHeader(key,value)方法
                setDateHeader(key,value)方法-专门修改日期类型的响应头
                setIntHeader(key,value)方法 - 专门修改int类型的响应头
        空行
        正文
            getWriter() 修改字符类型的正文(文本,网页)minetype:text/*类型
            getOutputStream() 修改字节类型的正文(图片,视频)
    getOutputStream()返回文本数据解决乱码
        系统默认是GBK
            ServletOutputStream outputStream = res.getOutputStream();
            String str = "帅哥";
            outputStream.write(str.getBytes());
        输出其它编码
            ServletOutputStream outputStream = res.getOutputStream();
            第一种方式
            仅仅在ie浏览器有效
            String meta = "<meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
            //String meta = "<meta charset='UTF-8'>";
            outputStream.write(meta.getBytes());
            第二种方式
            所有浏览器有效
            response.setHeader("content-type", "text/html; charset=UTF-8");
            第三种方式
            所有浏览器有效
            response.setContentType("text/html; charset=UTF-8");
            String str = "帅哥";
            outputStream.write(str.getBytes("UTF-8"));
    getWriter()返回文本数据解决乱码
        write方法默认是iso-8859-1
            只能输出字节
        输出其它编码
            修改输出字符内容的查询编码-修改的是服务器- 这个代码可以省略
                response.setCharacterEncoding("UTF-8");
            通知浏览器使用正确的编码解析
                response.setContentType("text/html; charset=UTF-8");
                PrintWriter writer = response.getWriter();
                默认编码是iso-8859-1
                writer.write("帅哥");
    文件下载
        读取文件
            String path = getServletContext().getRealPath("/file/开发0710学生情况.xlsx");
            File file = new File(path);
            FileInputStream inputStream = new FileInputStream(file);
            获取输出通道
            ServletOutputStream outputStream = response.getOutputStream();
            下载提示框 响应头 content-disposition
            注意:在浏览器和服务器之间请求头和响应头内容出现中文,不能直接传输,而应该把中文内容进行URL编码才能传输
            String filename = URLEncoder.encode(file.getName(),"UTF-8");
            response.setHeader("content-disposition", "attachment;filename="+filename);
            边读边写
            byte[] buf = new byte[1024];
            int len = 0;
            while((len =inputStream.read(buf))!= -1){
                outputStream.write(buf);
            }
            关闭流
            inputStream.close();
    输出随机验证码(防止恶意注册和登录)
        public void writeImage(HttpServletResponse response)throws ServletException, IOException {
            //内存生成一张图片
            int width = 120;
            int height = 50;
            BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
            //修改图片背景
            //得到画笔
            Graphics graphics = image.getGraphics();
            //绘制背景
            graphics.setColor(Color.gray);
            //绘制形状
            graphics.fillRect(0, 0, width, height);
            //设置字体
            graphics.setFont(new Font("黑体", Font.ITALIC, 30));
            //绘制数字
            graphics.setColor(Color.BLACK);
            String str = "1234";
            graphics.drawString(str, 20, 25);
            //设置随机干扰线
            Random ran = new Random();
            for(int i=1;i<=20;i++){
                int x1 = ran.nextInt(width);
                int y1 = ran.nextInt(height);
                int x2 = ran.nextInt(width);
                int y2 = ran.nextInt(height);
                //随机色
                graphics.setColor(getRanColor());
                graphics.drawLine(x1, y1, x2, y2);
            }
            //把这个图片写出给浏览器
            ServletOutputStream outputStream = response.getOutputStream();
            ImageIO.write(image, "gif", outputStream);
        }
        //获取随机颜色
        private  Color getRanColor(){
            Random ran = new Random();
            int r = ran.nextInt(256);
            int g = ran.nextInt(256);
            int b = ran.nextInt(256);
            return new Color(r,g,b);
        }
        页面使用
            ![](one)
    重定向
        发出两次请求
        地址栏会发生变化
        可以重定向任何资源(包括应用外的资源)
        不可以通过request来共享数据
        代码
            response.sendRedirect("/info.jsp");
    

    HttpServletRequest对象

    概述
        表示请求对象,包含所有的请求数据。使用request获取请求的数据。
    请求格式
        请求行
            请求方式  request.getMethod()
            请求资源  request.getRequestURL() / request.getRequestURI()
            http版本  request.getProtocol()
            获得get请求的参数 request.getQueryString()
        请求头
            获得一个请求头 getHeader(key) 
            获得整形的请求头 getIntHeader(key) 
            获得日期类型的请求头 getDateHeader(key) 
        空行
        正文
            获得正文 getInputStream()
    防盗链
        String referer = request.getHeader("referer");
        if(referer == null || !referer.contains("/servlettest")){
            //非法连接
            return;
        }
    获取表单数据
        get : getQueryString()
        post : getInputStream()
        通用方式 
            获取某个参数 getParameter("")
            获取某个参数的集合 getParameterValues("") 例如:checkbox
            获取所有的参数名 getParameterNames()
            获取所有的参数 getParameterMap()
    乱码问题
        if("post".equalsIgnoreCase(request.getMethod())){
            //只能解决post提交的参数,不能解决get提交的参数,因为这个方法只能设置请求正文的内容
            request.setCharacterEncoding("UTF-8");
        }
        String name = request.getParameter("name");//默认是iso-8859-1
        if("get".equalsIgnoreCase(request.getMethod())){
            //get请求的参数需要手动解码
            name = new String(name.getBytes("iso-8859-1"),"UTF-8");
        }
    转发
        发出一次请求
        地址栏不会发生变化
        只能转发应用内的资源
        可以通过request来共享数据
        代码
            //可以把数据发到转发的页面
            req.setAttribute("name", "zhangshuai");
            //第一种方式
            getServletContext().getRequestDispatcher("/info.jsp").forward(req, response);
            //第二种方式
            req.getRequestDispatcher("/info.jsp").forward(req, response);
    

    beanutils封装参数

    下载
        https://commons.apache.org/proper/commons-beanutils/
        http://commons.apache.org/proper/commons-logging/ 依赖包
    导包
      commons-beanutils-1.9.3.jar
      commons-logging-1.2.jar
    页面
        <form action="/easyuitest/one" method="post">
            用户名:<input type="text" name="name" /><br /> 
            密码:<input type="password" name="password" /><br /> 
            爱好: <input type="checkbox" name="hobby" value="eat" />吃 
                <input type="checkbox" name="hobby" value="sleep" />睡
                <input type="checkbox" name="hobby" value="play" />玩<br /> 
            <input type="submit" value="提交" />
        </form>
    后台工具类
        public static <T> T transform(Class clazz, HttpServletRequest req) throws Exception {
            String method = req.getMethod();
            if ("post".equalsIgnoreCase(method)) {
                req.setCharacterEncoding("UTF-8");
            }
            Object instance = null;
            instance = clazz.newInstance();
            BeanUtils.populate(instance, req.getParameterMap());
            if ("get".equalsIgnoreCase(method)) {
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    String name = field.getName();
                    char charAt = name.charAt(0);
                    String upperCase = String.valueOf(charAt).toUpperCase();
                    String name2 = "set" + upperCase + name.substring(1);
                    String name1 = "get" + upperCase + name.substring(1);
                    Method method2 = clazz.getMethod(name2, field.getType());
                    Method method3 = clazz.getMethod(name1);
                    Class type = field.getType();
                    Class s = String.class;
                    String invoke = (String) method3.invoke(instance);
                    if (s.equals(type)) {
                        invoke = new String(invoke.getBytes("iso-8859-1"), "UTF-8");
                    }
                    method2.invoke(instance, invoke);
                }
            }
            return (T) instance;
        }
    servlet中使用
        User user = WebUtils.fillBean(request,User.class);
        System.out.println(user);
    注意
        User中的属性一定要跟jsp中的属性一致。
    原理
        private void datatoentity(HttpServletRequest request) {
            try {
                //约定:表单的每个控件name属性值 和 需要封装的对象的属性名称保持一致!!
                User user = new User();
                //获取所有参数
                Map<String,String[]> map = request.getParameterMap();
                for(Entry<String,String[]> entry: map.entrySet()){
                    //参数名称(相当于对象的属性名)
                    String paramName = entry.getKey();
                    //参数值
                    String[] paramValue = entry.getValue();
                    //得到对象的属性(Field)
                    //得到类对象
                    Class clazz = user.getClass();
                    //获取类的某个属性(Field)
                    Field field = clazz.getDeclaredField(paramName);
                    //暴力反射
                    field.setAccessible(true);
                    //给属性赋值
                    //如果参数值有多个,则存入数组,否则存入数组的第一个元素
                    if(paramValue.length>1){
                        //赋值
                        field.set(user, paramValue);
                    }else{
                        field.set(user, paramValue[0]);
                    }
                }
                System.out.println(user);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    路径问题

    浏览器行为   指向主机的根目录 tomcat/webapps
    服务器行为   指向当前web应用的根目录  项目名称servlettest
    服务端  项目根目录
        服务器行为
            getServletContext().getRealPath("/");
        服务器行为
            getServletContext().getResourceAsStream("/");
        服务器行为
            req.getRequestDispatcher("/");
        服务器行为  /是否开头都一样
            <%@ page errorPage="/" %>
        服务器行为 /是否开头都一样
            <%@ include file="/" %>
    浏览器  tomcat/webapps目录
        浏览器行为
            resp.sendRedirect("/");
        浏览器行为
            /onetest/one 绝对路径,tomcat/webapps
            one 相对路径,默认是项目根目录
            <form action="/">
        浏览器行为
            /onetest/two 绝对路径,tomcat/webapps
            two 相对路径,默认是项目根目录
            <a href="/" />
        浏览器行为
            one.css 相对路径 
            /onetest/one.css 绝对路径 
            <link rel="stylesheet" type="text/css" href="/" />
        浏览器行为
            /onetest/info.js 绝对路径      
            info.js 相对路径,可以这样写,根目录就是项目 目录
            <script type="text/javascript" src="/"></script>
        浏览器行为-超链接 
            response.getWriter().write("<a href='/项目名/路径'>超链接</a>");
        浏览器行为-表单
            response.getWriter().write("<form action='/项目名/路径'></form>");
    

    会话管理

    概述
        好比是一次通话。从打开浏览器,访问多次服务器资源,关闭浏览器,这个过程就一次会话。
        是客户与Web服务器间一连串的交互过程。
        会话管理就是解决多个请求数据共享的问题。
            例如:多个用户使用浏览器与服务器进行会话的过程中,服务器怎样会每个用户保存这些数据。
    两种技术
        Cookie技术:客户端技术,数据是保存在浏览器的缓存中
            定义:Cookie是一些数据,从Servlet发给浏览器,在浏览器中保存,然后通过浏览器发回给服务器。
            属性:
                name : cookie的名称
                value : cookie的数据
                comment : 注释
                path : 保存的路径
                domain : 保存的主机
                maxAge : cookie存活的时间
                    负数:Cookie存活在浏览器内存,浏览器关闭Cookie丢失
                    正数:Cookie存活在缓存文件中,只有删除缓存文件Cookie才会丢失。
                    零  :立即过期,用于删除同名的Cookie
                version : cookie的版本
            servlet方法
                添加 addCookie()
                接收 getCookies()
            限制
                1)类型必须是字符串
                2)cookie的长度不能超过4k,一个网站1次只能最多发20个,所有网站一共发300个
                3)数据保存浏览器,安全性差
            优点
                利用浏览器资源,减轻服务器压力
        HttpSession技术:服务器端技术,数据时保存在服务器内存中的
            是一个域对象
            获取方式
                HttpSession session = request.getSession();
            常用方法
                setAttribute(key,value)
                getAttribute(key)
            特点
                增加服务器压力
                任意数据类型
                大小没有限制
                相对安全
    

    Cookie

    创建Cookie
        Cookie cookie = new Cookie("name","shuaige");
        /*
         * 设置Cookie存活时间
         * 负数:Cookie存活在浏览器内存,浏览器关闭Cookie丢失
         * 正数:Cookie存活在缓存文件中,只有删除缓存文件Cookie才会丢失。
         * 零  :立即过期,用于删除同名的Cookie
         * */
        cookie.setMaxAge(Integer.MAX_VALUE);
        //默认路径 /项目名
        cookie.setPath("/servlet/servlettest");
        //发送给浏览器
        response.addCookie(cookie);
    每次浏览器请求会默认带着Cookie
        //接收Cookie
        //注意什么情况可以取出Cookie发送到服务器?  获取Cookie路径.startWith(Cookie的保存路径)=true的情况下可以获取。
        //注意:如果把Cookie的保存路径设置为当前Web应用的根目录,那么在当前web应用下所有访问资源时都能取出该Cookie
        Cookie[] cookies = request.getCookies();
        for(int i = 0;i<cookies.length;i++){
            Cookie cookie1 = cookies[i];
            System.out.println(cookie1);
        }
    获取用户上次访问的时间
    
    用Cookie来记录浏览过的商品
    
    
    domain表示的是cookie所在的域,默认为请求的地址
        同域访问
            http://bbs.shuaige.com/onttest/one的默认域名是bbs.shuaige.com
        跨域访问
            http://bbs.shuaige.com/onttest/one
            http://aas.shuaige.com/onetest/one
            设置domain为.shuaige.com就可以跨域访问了。
            本域设置不可以访问的
            例如http://bbs.shuaige.com/onttest/one设置不可以访问,并且http://aas.shuaige.com/onetest/one可以访问的
            设置domain为aas.shuaige.com就可以跨域访问了。
            path是cookie所在目录
            浏览器会将domain和path都相同的cookie保存在一个文件里,cookie间用*隔开
    

    HttpSession

    存值
        //获取session
        HttpSession session = request.getSession();
        //把数据存到session中
        session.setAttribute("name", "shuaige");    
    取值
        //获取session
        HttpSession session = request.getSession();
        //把数据从session中取出
        String name = (String)session.getAttribute("name");
        System.out.println(name);
    request.getSession()方法
        1.查询服务器中是否存在对应的HttpSession对象
            有:返回对应的对象
            没有:创建一个新的对象返回
        2.HttpSession对象会设置一个对应浏览器的JSESSINOID,通过请求头(set-cookie)实现。
            HttpSession session = request.getSession();
            String sid = session.getId();
            服务器也是根据这个JSESSINOID来取出对应的session
        3.注意:
            request.getSession(true)/request.getSession()
                查询服务器中是否存在对应的HttpSession对象
                    有:返回对应的对象
                    没有:创建一个新的对象返回
            request.getSession(false)
                查询服务器中是否存在对应的HttpSession对象
                    有:返回对应的对象
                    没有:返回null
    原理
        HttpSession对象会设置一个对应浏览器的JSESSINOID,通过请求头(set-cookie)实现。
            HttpSession session = request.getSession();
            String sid = session.getId();
            服务器也是根据这个JSESSINOID来取出对应的session
    购物车
    
    会员登录
    
    HttpSession钝化与激活
        正常关闭服务
        HttpSession对象过久没有访问
    

    第三方控件-上传

    概述
        由非软件提供商提供的功能组件
        commons-fileupload文件上传组件
            Apache提供的实现文件上传的组件
            免费的、开源的
    commons-fileupload API
        FileItemFactory接口
            用于构建FileItem实例
        DiskFileItemFactory类
            是FileItemFactory接口实现类
            FileItemFactory  factory = new DiskFileItemFactory();
        ServletFileUpload类
            组件的核心类
            封装表单元素并以集合方式返回
            ServletFileUpload(FileItemFactory  fileitemfactory)
            boolean isMultipartContent (HttpServletRequest request)
                静态方法。用于判断请求数据中的内容是否是multipart/form-data类型。是返回true,否返回false
            List parseRequest(HttpServletRequest request)
                将请求数据中的每一个字段,单独封装成FileItem对象,并以List方式返回
        FileItem类
            封装表单元素的数据
            具有对表单内容处理的方法
            常用方法
                String getFieldName() 返回表单字段元素的name属性值
                boolean isFormField() 判断FileItem封装的数据是属于普通表单字段,或者是文件表单字段。普通表单字段:true,文件表单字段:false。
                String getName() 返回上传文件字段中的文件名,文件名通常是不含路径信息的,取决于浏览器实现
                void write(File file) 将FileItem对象中的内容保存到指定文件中
                String getString() 按照默认编码格式返回字符串
                String getString(String encoding) 按照指定编码格式将内容转换成字符串返回
    使用步骤
        1.获取commons-fileupload组件
            commons-fileupload-版本号.jar
            commons-io-版本号.jar
        2.导入jar包
        3.设置表单提交属性
            <form  name="form1"  method="post" enctype="multipart/form-data" />
        4.实现Servlet中的上传
            4.1判断请求数据中的内容是否是multipart/form-data类型ServletFileUpload.isMultipartContent(req)
            4.2创建FileItemFactory实例new DiskFileItemFactory()
            4.3创建ServletFileUpload实例new ServletFileUpload(factory)
            4.4解析request请求,获取表单元素对应的FileItem集合upload.parseRequest(req)
            4.5循环遍历获取数据
            4.6判断元素类型,true-普通表单元素,false-文件元素item.isFormField()
            4.7如果是文件元素
                4.7.1获取文件名称item.getName()
                4.7.2如果有名称乱码就处理乱码new String(name.getBytes("GBK"),"UTF-8")
                4.7.3写出到指定位置item.write(file)
        代码
            <form action="one" enctype="multipart/form-data" method="post">
                <input name="username" type="text"/>
                <input name="file" type="file" />
                <input type="submit" value="提交">
            </form>
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                boolean isMultipart = ServletFileUpload.isMultipartContent(req);
                if(isMultipart){
                    //创建FileItemFactory实例
                    //参数一:代表缓存大小。假如设置的大小是1M,如果上传的文件不超过1M,那么不用缓存,如果超过1M,就使用缓存
                    //参数二:代表缓存的目录。
                    //DiskFileItemFactory factory = new DiskFileItemFactory(1024*1024,new File("C:\\tempFiles"));
                    FileItemFactory factory = new DiskFileItemFactory();
                    //创建ServletFileUpload实例
                    ServletFileUpload upload = new ServletFileUpload(factory);
                    try {
                        //限制文件大小(限制单个文件不超过200KB,总文件大小不超过500KB)
                        //upload.setFileSizeMax(200*1024);//限制单个文件不超过200KB
                        //upload.setSizeMax(500*1024);//总文件大小不超过500KB
                        List<FileItem> list = upload.parseRequest(req);
                        for(FileItem item : list){
                            if(!item.isFormField()){
                                
                                //限制文件类型(只能上传图片文件)  mime类型: text/plain image/*
                                String contentType = item.getContentType();
                                if(!contentType.matches("image/[a-zA-Z]+")){
                                    request.setAttribute("msg", "只允许上传图片格式的文件!");
                                    request.getRequestDispatcher("/upload4.jsp").forward(request, response);
                                    return;
                                }
                            
                                String name = item.getName();
                                name = new String(name.getBytes("GBK"),"UTF-8");
                                String savePath = "f:\\"+name;
                                File file = new File(savePath);
                                item.write(file);
                            }else{
                                System.out.println("表单元素:"+item.getFieldName()+"-"+item.getString());
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
    

    分页

    优势
        数据能够按照指定格式显示,布局清晰
        不受信息数量的限制
    不足
        当数据量较多,页面显示不完全时,需要用户拖动页面才能浏览更多信息
    实现
        Dao中
            1.获取表中数据总条数 int getCount();
            2.获取指定显示的条目 List<User> getUser(int start,int count);
        Service中
            1.每页显示条目个数
                int pagenum = 6;
            2.计算页数int getTotalPageCount()
                public int getTotalPageCount(){
                    int count = getCount();
                    int num = count / pagenum;
                    if(count%pagenum != 0){
                        num = num+1;
                    }
                    return num;
                }
            3.获取指定显示的条目
                public List<User> getUsers(int pageIndex){
                    int start = (pageIndex-1)*pagenum;
                    List<User> user = userDao.getUser(start, pagenum);
                    return user;
                }
        Controller中
            1.获取页面总条目
                String totalPageCountStr = req.getParameter("totalPageCount");
                int totalPageCount = 0;
                if(totalPageCountStr != null){
                    totalPageCount = Integer.valueOf(totalPageCountStr);
                }else{
                    totalPageCount = service.getTotalPageCount();
                }
            2.获取当前显示多少页
                String pageIndexStr = req.getParameter("pageIndex");
                int pageIndex = 1;
                if(pageIndexStr != null){
                    pageIndex = Integer.valueOf(pageIndexStr);
                }
            3.获取需要显示的数据
                List<User> users = service.getUsers(pageIndex);
            4.设置返回参数
                req.setAttribute("pageIndex", pageIndex);
                req.setAttribute("totalPageCount", totalPageCount);
                req.setAttribute("users",users);
        jsp中
            显示数据
                <table border="1">
                    <tr>
                        <th>id</th>
                        <th>name</th>
                        <th>age</th>
                    </tr>
                    <c:forEach items="${users}" var="user">
                        <tr>
                            <td>${user.id }</td>
                            <td>${user.name }</td>
                            <td>${user.age }</td>
                        </tr>
                    </c:forEach>
                </table>
            显示所有页数的链接
                <% 
                    int totalPageCount = (Integer)request.getAttribute("totalPageCount");
                    int pageIndex = (Integer)request.getAttribute("pageIndex");
                    for(int i = 1;i<=totalPageCount;i++){
                        StringBuffer sb = new StringBuffer();
                        if(i == pageIndex){
                            sb.append("<a style='padding: 5px;'>");
                        }else{
                            sb.append("<a href='one?pageIndex=");
                            sb.append(i);
                            sb.append("&totalPageCount=");
                            sb.append(totalPageCount);
                            sb.append("' style='padding: 5px;'>");
                        }
                        sb.append(i);
                        sb.append("</a>");
                        out.write(sb.toString());
                    }
                %>
    

    Servlet注解配置

    @WebServlet("/login")
    

    手动文件上传

    //1)读取请求正文
    InputStream in = request.getInputStream();
    //2)转换为字符读取流
    BufferedReader br = new BufferedReader(new InputStreamReader(in));
    //3)第一行:读取文件的分割符
    String fileTag = br.readLine();
    //4)第二行:读取文件名称
    String line = br.readLine();
    String fileName = line.substring( line.lastIndexOf("filename=\"")+10 , line.length()-1);
    //跳过两行
    br.readLine();
    br.readLine();
    //5)读取文件内容
    String str = null;
    BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\targetFiles\\"+fileName));
    //不断读取
    while(  (str=br.readLine())!=null ){
        //忽略文件的分割符
        if( (fileTag+"--").equals(str)){
            break;
        }
        bw.write(str);//写出一行
        bw.newLine();//换行符
    }
    bw.close();
    br.close();
    

    相关文章

      网友评论

          本文标题:Servlet

          本文链接:https://www.haomeiwen.com/subject/oojssxtx.html