javaee(servlet)

本文介绍了编码解码的基本概念及应用,详细讲解了如何在服务器端设置字符编码以正确处理中文字符,同时探讨了文件下载过程中文件名的编码处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 1.编码和解码

当内存中的数字被解释为字符(文字和符号)时,就是解码过程,把文字和符号用数字定义时就是编码。

        //服务器默认编码为ISO8859-1,它不支持中文,tomcat规定的
        //resp.setCharacterEncoding("UTF-8");//指定对服务器响应进行重新编码的编码
        //指定对服务器响应进行响应头的设置,告诉浏览器响应头的字符集格式是UTF-8。
        //resp.setHeader("Content-Type","text/html;charset=utf-8");
        //指定对服务器响应进行重新编码的编码,和告诉浏览器响应字符集格式是UTF-8。
        resp.setContentType("text/html;charset=UTF-8");
        ServletOutputStream outputStream = resp.getOutputStream();
        outputStream.write("哈哈".getBytes("utf-8"));//默认采用本地编码gbk
        PrintWriter writer = resp.getWriter();
        writer.write("你好");

2.文件下载

文件名的编码问题,和设置响应头为下载

	//通过路径得到一个输入流
        String path = this.getServletContext().getRealPath("/WEB-INF/classes/05.jpg");
        FileInputStream fis=new FileInputStream(path);
        //创建输出流,输出浏览器
        ServletOutputStream outputStream = resp.getOutputStream();
        //得到要下载的文件名
        String substring = path.substring(path.lastIndexOf("\\") + 1);
        System.out.println(substring);
        //设置文件名编码
        URLEncoder.encode(substring,"UTF-8");
        resp.setHeader("content-disposition","attachment;filename="+substring);
        //执行输出
        int len=0;
        byte[] b=new byte[1024];
        while((len=(fis.read(b)))!=-1){
            outputStream.write(b,0,len);
        }

3.验证码

设置验证码图片

@WebServlet(urlPatterns = "/demo3")
public class ServletDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        int width=110;
        int height=25;
        //在内存中创建一个图像对象
        BufferedImage img=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //创建一个画笔
        Graphics g=img.getGraphics();
        //给图片添加背景色
        g.setColor(Color.GREEN);
        //xy为坐标,windth和height为高宽
        g.fillRect(1,1,width-2,height-2);
        //设置文本样式
        g.setColor(Color.BLACK);
        g.setFont(new Font("宋体",Font.BOLD,17));
        //给图片添加文本
        Random rand=new Random();
        int position=20;
        for (int i=0;i<4;i++){
            g.drawString(rand.nextInt(10)+"",position,20);
            position+=20;
        }
        //加上干扰线
        for (int i=0;i<9;i++){
            g.drawLine(rand.nextInt(width),rand.nextInt(height),rand.nextInt(width),rand.nextInt(height));
        }
        //将图片对象以流的方式输出客户端
        ImageIO.write(img,"jpg",resp.getOutputStream());
    }
}
jsp页面
<script type="text/javascript">
  function changeCode(){
      var img=document.getElementsByTagName('img')[0];
      //解决缓存问题
      img.src="${pageContext.request.contextPath}/demo3?time="+new Date().getTime();
  }
</script>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>
  <form>
    验证码:<input type="text"><img src="${pageContext.request.contextPath}/demo3">
    <a href="javascript:changeCode()">看不清换一张</a>
  </form>
  </body>
</html>
可以使用工具类实现验证码,需要引入ValidateCode.jar

刷新并且跳转网页

resp.setIntHeader("refresh",1);//1秒刷新页面
resp.setHeader("refresh","3;url="xxxxx");//设置3秒跳转xxxxx页面

转发和重定向

转发:浏览器地址不变,可以带request和response

重定向:浏览器地址会变,并且不能带request和response

基础(理解302是重定向,location是转换地址)

@WebServlet(urlPatterns = "/demo4")
public class ServletDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(302);//响应码302,告诉浏览器是重定向
        //重定向的位置
        resp.setHeader("location","http://write.blog.youkuaiyun.com/");
    }
}
进阶(此方法是对上面的代码进行封装,所以无非封装的都是响应头,响应行,响应消息体,而已,以后在别的语言没有sendRedirect方法,我们也知道怎么创造轮子)

resp.sendRedirect("url");

判断不同浏览器

@WebServlet(urlPatterns = "/demo5")
public class ServletDemo5 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String header = req.getHeader("User-Agent");
        System.out.println(header);
        if(header.toLowerCase().contains("msie")){
            System.out.println("你使用的是IE浏览器");
        }else if(header.toLowerCase().contains("firefox")){
            System.out.println("你使用的是火狐浏览器");
        }else if(header.toLowerCase().contains("chrome")){
            System.out.println("你使用谷歌浏览器");
        }
    }
}

解决请求参数乱码问题

post 乱码问题

req.setCharacterEncoding("utf-8"); //设置请求编码格式 注:浏览器使用什么编码传过来就是什么编码

get乱码问题

String name=new String(name.getBytes("ISO-8859-1"),"UTF-8");



内省(Introspector) JavaBean

基础:开发框架时,经常需要使用java对象的属性来封装数据,每次用反射技术过于麻烦,所以sun公司提供了一套api,专门操作java对象的属性。

 public static void main(String[] args) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        //创建Student对象
        Student s=new Student();
        //获取Student类中的name属性
        PropertyDescriptor pd=new PropertyDescriptor("name",Student.class);
        Method writeMethod = pd.getWriteMethod();
        Method readMethod = pd.getReadMethod();
        //设置s对象中name属性为小明
        writeMethod.invoke(s,"小明");
        //获取s对象中name的属性值
        System.out.println(readMethod.invoke(s, null));
    }

高级:使用内省对request的请求参数进行封装(前提,实体类和请求参数name一致!)

      Map<String, String[]> map = req.getParameterMap();
        Student s=new Student();
        for (Map.Entry<String,String[]> m:map.entrySet()) {
            String key = m.getKey();
            String[] value = m.getValue();
            try {
                //获取当前Student中表单对应的key对应的Student的属性
                PropertyDescriptor descriptor = new PropertyDescriptor(key, Student.class);
                //创建属性描述器
                if(value.length==1){
                    writeMethod.invoke(s,value[0]);//给一个值的变量赋值
                }else{
                    writeMethod.invoke(s,(Object) value);//多个值的变量赋值(如复选框)
                }
            } catch (IntrospectionException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }

终极:使用commons-beanutils.jar对属性进行封装,使用前提还需要commons-logging.jar日志架包

   Map<String, String[]> map = req.getParameterMap();
        Student s=new Student();
        for (Map.Entry<String,String[]> m:map.entrySet()) {
            String key = m.getKey();
            String[] value = m.getValue();
            try {
                //使用beanUtiles框架的好处就是一步到位,简单
                BeanUtils.populate(s,map);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

请求包含

forward()方法

    • forward()方法的处理流程如下:(1)清空用于存放响应正文数据的缓冲区;(2)如果目标组件为Servlet或JSP,就调用它们的service()方法,把该方法产生的响应结果发送到客户端,如果目标组件为文件系统中的静态html文档,就读去文档中的数据并把它发送到客户端。
    • 由于forward()方法先清空用于存放响应正文数据的缓冲区,因此servlet源组件生成的响应结果不会被发送到客户端,只有目标组件生成的结果才会被发送到客户端;
    • 如果源组件在进行请求转发之前,已经提交了响应结果(例如调用了flushBuffer方法,或者close()方法),那么forward()方法会抛出IllegalStateException。为了避免该异常,不应该在源组件中提交响应结果。

  • include()方法
  • 源主键与被包含的组件输出的数据都将添加响应结果中
  • 在目标组件中对响应状态代码或者响应头所做的修改都会被忽略










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值