Сервлет Часть III [Введение в запрос и ответ, общие применения ответа]

Java Java EE
Сервлет Часть III [Введение в запрос и ответ, общие применения ответа]

ответ, объект запроса

Tomcat получает http-запрос от клиента и создает отдельный для каждого запроса.Объект запроса, представляющий запрос,а такжеобъект ответа, представляющий ответ

Поскольку объект запроса представляет собой HTTP-запрос, мыПолучить данные, отправленные браузером, и найти объект запросаВот и все. Объект ответа представляет ответ http, затем мыВывести данные в браузер и найти объект ответаВот и все.

Что такое объект HttpServletResponse?

HTTP-ответ состоит из строки состояния, содержимого сущности, заголовков сообщений и пустой строки.Объект HttpServletResponse инкапсулирует информацию ответа http.

Применение HttpServletResponse

Вызовите метод getOutputStream() для вывода данных в браузер.

  • Вызовите метод getOutputStream() для вывода данных в браузер,Метод getOutputStream() может использовать print() или write()., какая между ними разница? Давайте попробуем. код показывает, как показано ниже

        //获取到OutputStream流
        ServletOutputStream servletOutputStream = response.getOutputStream();

        //向浏览器输出数据
        servletOutputStream.print("aaaa");
  • Выход успешный, вроде ничего страшного в этом нет.

  • Попробуем вывести китайский

        //获取到OutputStream流
        ServletOutputStream servletOutputStream = response.getOutputStream();

        //向浏览器输出数据
        servletOutputStream.print("中国!");
  • Что-то пошло не так! ! !

  • Почему есть исключение? В ио мы узнали,outputStream - это вывод двоичных данных,Метод print() получает строку,Метод print () должен преобразовать «Китай» в двоичные данные, Tomcat использует кодировку IOS 8859-1 для его преобразования, «Китай» вообще не поддерживает кодировку ISO 8859-1.. Так что есть исключение
  • Давайте еще раз посмотрим на метод write(), сначала выводя данные на английском языке в браузер.

		response.getOutputStream().write("aaa".getBytes());

  • нет проблем

  • Попробуйте снова вывести китайские данные

	 response.getOutputStream().write("你好呀我是中国".getBytes());


  • Кажется, нет проблем.

  • Зачем использовать метод write() для нормального вывода китайского языка в браузер?"你好呀我是中国".getBytes()Этот код находится вПри преобразовании в массив byte[] по умолчанию используется кодировка gb2312., а **"Привет, я из Китая" поддерживает кодировку gb2312**, поэтому может отображаться нормально.
  • Тем не менее, программаДля универсальности следует использовать кодировку UTF-8.,мы вУкажите кодировку UTF-8 при преобразовании строки в массив байтов, и посмотрим, что произойдет.

 	response.getOutputStream().write("你好呀我是中国".getBytes("UTF-8"));

  • Хорошо, успешно испортил это! ! !

  • Почему оно стало искаженным? Причина в следующем: я вывожу на серверКитайский кодируется в UTF-8, а браузер использует GBK, который хочет отображать китайские данные в UTF-8.!

  • В этом случае я попробую изменить кодировку браузера на UTF-8.

  • Испорченная проблема снова решена. Однако каждый разНужно ли переходить на веб-страницу, чтобы изменить формат кодировки при написании программ UTF-8? это очевидно невозможно.
  • Поскольку ответ HTTP имеет заголовок сообщения, который сообщает браузеру, какой тип данных отправляется обратно, объект HttpServletResponse должен иметь соответствующий метод, сообщающий браузеру, какой формат кодирования данных.
  • Итак, я пошел искать Servlet API и нашел его.Как настроить заголовки сообщений

        //设置头信息,告诉浏览器我回送的数据编码是utf-8的
        response.setHeader("Content-Type", "text/html;charset=UTF-8");
        
        response.getOutputStream().write("你好呀我是中国".getBytes("UTF-8"));



  • Когда браузер отображает данные, он автоматически заменяет формат кодировки страницы на UTF-8., проблема с искажениями также решена

  • Кроме того, вместо использования метода объекта HttpServletResponse для установки заголовков сообщений я могуИспользуйте HTML-теги для имитации заголовка HTTP

  • Вот код:


        //获取到servletOutputStream对象
        ServletOutputStream servletOutputStream = response.getOutputStream();


        //使用meta标签模拟http消息头,告诉浏览器回送数据的编码和格式
        servletOutputStream.write("<meta http-equiv='content-type' content='text/html;charset=UTF-8'>".getBytes());

        servletOutputStream.write("我是中国".getBytes("UTF-8"));


  • Искаженная проблема также может быть решена

Вызовите метод getWriter() для вывода данных в браузер.

  • Для метода getWriter() это подкласс Writer, тогдаМожет выводить в браузер только символьные данные, а не двоичные данные
  • Используйте метод getWriter() для вывода данных на китайском языке, код выглядит следующим образом:

        //获取到printWriter对象
        PrintWriter printWriter = response.getWriter();
        printWriter.write("看完博客点赞!");


  • То, что мне нравится слышать и видеть, произошло снова, и я снова исказил символы.

  • Почему существует искаженный код? Поскольку Tomcat написан иностранцами,Кодировка Tomcat по умолчанию — ISO 8859-1., когда мы выводим китайские данные,Tomcat будет кодировать наши данные в соответствии с кодовой таблицей ISO 8859-1. Китайский язык не поддерживает эту кодовую таблицу., так что там искажено
  • В таком случае, почему бы мне не установить кодировку?Код выглядит следующим образом:
		

        //原本是ISO 8859-1的编码,我设置成UTF-8
        response.setCharacterEncoding("UTF-8");

        //获取到printWriter对象
        PrintWriter printWriter = response.getWriter();
        printWriter.write("看完博客点赞!");



  • Я посетил снова и о мой! Это выглядит грязнее!

  • Почему до сих пор не решена кривая проблема? Внимательные друзья обнаружат, что я всего лишьПри преобразовании китайского языка установите кодовую таблицу в UTF-8.,ноБраузер не обязательно использует кодовую таблицу UTF-8 для отображения данных.
  • Хорошо, давайте посмотрим на формат кодировки браузера, браузер использует GB2312 для отображения данных UTF-8.

  • Мы уже решили эту проблему двумя способами [используя теги для имитации заголовков сообщений и устанавливая заголовки сообщений], и Servlet также предоставляет нам метод

        //设置浏览器用UTF-8编码显示数据
        response.setContentType("text/html;charset=UTF-8");

  • Ладно, зайдем еще

  • Поскольку в Servlet так много способов решить проблему искаженных символов, есть ли самый простой? Вот так! Следующий способ самый простой, онНе только настройте браузер на использование UTF-8 для отображения данных, но также установите внутреннюю кодовую таблицу китайского транскодирования на UTF-8., то есть,response.setContentType("text/html;charset=UTF-8");Пучокresponse.setCharacterEncoding("UTF-8")дела сделаны!

  • Используйте getWriter() для отображения данных на китайском языке, вам нужен только один метод!


        //设置浏览器用UTF-8编码显示数据,
        response.setContentType("text/html;charset=UTF-8");

        //获取到printWriter对象
        PrintWriter printWriter = response.getWriter();
        printWriter.write("看完博客点赞!");



Реализовать загрузку файлов

Скачивание ресурсов также очень распространено в нашей повседневной жизни, как это делается?Чтобы иметь возможность скачивать для других, на сервере должен быть этот ресурс

  • Теперь у меня есть фотография под моим сайтом!

  • Так как все запросы на поиск сервлета отправляет браузер, то я напишу сервлет,Когда другие посещают мой сервлет, они могут скачать мою картинку!

  • Загрузка и скачивание файлов в java выполняются через поток io.Поскольку вы хотите загрузить изображение, вы должны сначала иметь возможность его прочитать.


        //获取到资源的路径
        String path = this.getServletContext().getRealPath("/download/1.png");

        //读取资源
        FileInputStream fileInputStream = new FileInputStream(path);

        //获取到文件名,路径在电脑上保存是\\形式的。
        String fileName = path.substring(path.lastIndexOf("\\") + 1);

  • Сообщить браузеру, что я хочу скачать этот файл

	    //设置消息头,告诉浏览器,我要下载1.png这个图片
        response.setHeader("Content-Disposition", "attachment; filename="+fileName);

  • Отправить прочитанное содержимое обратно в браузер

        //把读取到的资源写给浏览器
        int len = 0;
        byte[] bytes = new byte[1024];
        ServletOutputStream servletOutputStream = response.getOutputStream();

        while ((len = fileInputStream.read(bytes)) > 0) {
            servletOutputStream.write(bytes, 0, len);
        }

        //关闭资源
        servletOutputStream.close();
        fileInputStream.close();
  • Когда я захожу, браузер предлагает загрузить.

  • Его также можно успешно открыть!

  • Теперь опять проблема, а что если имя моего файла китайское?

  • Давайте снова зайдем и обнаружим, что имя искажено (хотя оно искажено)

  • Чтобы решить искаженное имя файла, нам нужно выполнить кодирование URL, код показан ниже:

        response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));

  • При повторном доступе проблема с искаженными именами файлов решена!


Реализовать автоматическое обновление

Обновляйте страницу в указанное время для обновления ресурсов

  • Пусть браузер достигнет автоматического обновления, он должен снова модифицировать заголовок сообщения.

        //每3秒自动刷新网页一次
        response.setHeader("Refresh", "3");

  • Чтобы лучше видеть результаты, мы добавляем ценность во время

	response.getWriter().write("time is :" + System.currentTimeMillis());
	
  • Значение времени меняется каждые три секунды

  • После изучения вышеизложенного кажется, что это бесполезно.Кто может видеть такие вещи, когда они в сети.Автоматическое обновление, способное реализовать переход на страницу
  • После того, как мы войдем на сайт, много раз мы увидим [Успешный вход, автоматический переход через 3 секунды....], на самом деле это делается с помощью Refresh.

	  	response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("3秒后跳转页面.....");

        //三秒后跳转到index.jsp页面去,web应用的映射路径我设置成/,url没有写上应用名
        response.setHeader("Refresh", "3;url='/index.jsp'");


  • Эффект взгляда


установить кеш

Сам браузер имеет механизм кэширования

  • Когда я впервые посетил index.jsp, браузер отправил на сервер два запроса [один для веб-страницы и один для изображения]

  • Когда я посещаю index.jsp во второй раз,Браузер кэширует изображение! Изображение не перезагружается, оно взято из кеша.

  • Веб-страницы, такие как типы акций, не могут получить доступ к кэшированным данным, и данные должны постоянно обновляться. Ниже я отключу функцию кеша

        //浏览器有三消息头设置缓存,为了兼容性!将三个消息头都设置了
        response.setDateHeader("Expires", -1);
        response.setHeader("Cache-Control","no-cache");
        response.setHeader("Pragma", "no-cache");


		//这里为了看效果
        PrintWriter printWriter = response.getWriter();
        printWriter.print("你好啊" + new Date().toString());


  • Конечно,Если какие-то данные на странице долго не обновляются, вы можете установить их как кеш, что может повысить производительность сервера

Реализовать сжатие данных

Объем информации на веб-странице очень велик, еслиНе сжимайте данные и не отправляйте их обратно в браузер, который очень интенсивно использует трафик.

  • Теперь у меня есть статья для вывода в браузер
        response.setContentType("text/html;charset=UTF-8");

        String ss = "fsdfhsdfhuisdhfusdhfuids" +
                "fsdfdsfsdfsdfdsfdafdsfhsdjfhsdjkfhkjds" +
                "fdsfjdslkfjsldkfjsdlkfjsdkfsdjkff" +
                "fsjdfjdsklfjdsklfjkldsfjlksdjflksdjflkds" +
                "dsjfklsdjflsdjfkldsfkjsdkfjsldkfjsdlfk" +
                "fdsjlkfjdslkfjsdlkfjlkasjflk";
        response.getWriter().write("原来的长度是:"+ss.getBytes().length+"</br>");

        //输出给浏览器
        response.getWriter().write(ss);


  • Посетите, чтобы увидеть,Оригинальная длина 201

  • Каков принцип сжатия? мы знаемИ getOutputStream(), и getWriter() выводят данные непосредственно в браузер.. Теперь все, что мне нужно сделать, этоЧтобы данные не выводились напрямую в браузер, позвольте мне сначала их сжать, а потом выводить в браузер.Java предоставляет нам класс сжатия GZIP.
  • Давайте используем класс GZIP для сжатия данных

        //GZIP的构造方法需要一个OutputStream子类对象,究竟哪个对象适合,我们看下write()方法
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream();

        //查看了下API,write()接收的是byte[]类型的。
        gzipOutputStream.write();

  • Так что яПередайте ему ByteArrayOutputStream в конструкторе


        //既然是byte[]类型,那么我就给他一个ByteArrayOutputStream
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new ByteArrayOutputStream());

  • и использоватьКогда GZIPOutputStream записывает данные, он записывает данные в ByteArrayOutputStream, а позже извлекает данные и записывает их в браузер., такВы не можете указать GZIPOutputStream как анонимный внутренний класс, вы должны определить ByteArrayOutputStream,

        //创建GZIPOutputStream对象,给予它ByteArrayOutputStream
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);

        //GZIP对数据压缩,GZIP写入的数据是保存在byteArrayOutputStream上的
        gzipOutputStream.write(ss.getBytes());

        //gzipOutputStream有缓冲,把缓冲清了,并顺便关闭流
        gzipOutputStream.close();


  • ПучокСжатые данные вынимаются и записываются в браузер
  		//将压缩的数据取出来
        byte[] bytes = byteArrayOutputStream.toByteArray();

        //将压缩的数据写给浏览器
        response.getOutputStream().write(bytes);

  • Сравним размер до сжатия и размер после сжатия

  • Данные действительно сжаты, но почему они снова искажены? очень просто, так какВы сжимаете данные, вы пишете их в браузер, браузер не знает, что это сжатые данные, он открывает данные в обычном режиме. Это, конечно, приводит к искажению символов! , теперь я хочуСкажите браузеру, что я сжимаю данные.

        //告诉浏览器这是gzip压缩的数据
        response.setHeader("Content-Encoding","gzip");

        //再将压缩的数据写给浏览器
        response.getOutputStream().write(bytes);

  • посетить снова


Генерировать случайные картинки

Очень часто генерируются случайные изображения.Когда мы входим в систему, нам часто приходится писать коды подтверждения, и эти коды подтверждения представляют собой картинку, которая записывается в браузер через HttpServletResponse.


  • Чтобы создать изображение,java предоставляет класс BufferedImage для использования


        //在内存中生成一张图片,宽为80,高为20,类型是RGB
        BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);

        //获取到这张图片
        Graphics graphics = bufferedImage.getGraphics();

        //往图片设置颜色和字体
        graphics.setColor(Color.BLUE);
        graphics.setFont(new Font(null, Font.BOLD, 20));

        //往图片上写数据,先写个12345,横坐标是0,纵坐标是20【高度】
        graphics.drawString("12345", 0, 20);


  • Хорошо, теперь создаем образ в памяти и пишем 12345. Далее мы будемЗаписать изображение в браузер.Запишите изображение в браузер, и java предоставит нам поток изображений [ImageIO].

        //要往浏览器写一张图片,那要告诉浏览器回送的类型是一张图片
        response.setHeader("ContentType", "jpeg");
        
        //java提供了图片流给我们使用,这是一个工具类
        //把图片传进去,类型是jpg,写给浏览器
        ImageIO.write(bufferedImage, "jpg", response.getOutputStream());

  • Давайте посетим и посмотрим, как выглядит картина

  • Это так некрасиво, давайте изменим фон на белый и посмотрим

        //把白色填充整张图片
        graphics.setColor(Color.white);
        graphics.fillRect(0, 0, 80, 20);

  • Посмотрите на эффект еще раз, он явно намного лучше

  • Хорошо, наши номера картинок не могут быть написаны от руки, числа должны генерироваться случайным образом! **Это просто. Теперь я хочу сгенерировать 7-значное случайное число, метод генерации случайного числа выглядит следующим образом


    private String makeNum() {

        Random random = new Random();

        //这样就会生成0-7位的随机数,现在问题又来了,如果随机数不够7位呢?如果不够7位,我们加到7位就行了
        int anInt = random.nextInt(9999999);

        //将数字转成是字符串
        String num = String.valueOf(anInt);

        //判断位数有多少个,不够就加
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < 7 - num.length(); i++) {
            stringBuffer.append("0");
        }

        return stringBuffer.append(num).toString();
        
    }

  • еслиЧтобы сгенерировать китайский язык, просто найдите таблицу сопоставления китайского языка..

перенаправить прыжок

Что такое редирект-прыжок? Нажмите на гиперссылку,Уведомить браузер о переходе на другую страницуЭто называется перенаправление. ** сообщает браузеру о переходе, что очень важно. **Есть два способа перехода между страницами:перенаправить и впередЧто касается того, когда использовать перенаправление и что использовать переадресацию, я подробно объясню, когда закончу говорить об объекте HttpServletRequest.

  • Давайте перенаправим, используя следующий объект HttpServletResponse

        //重定向到index.jsp页面
        response.sendRedirect("/zhongfucheng/index.jsp");

  • существуетАдресная строка браузера для доступа к Servlet222

  • Перейти на страницу index.jsp, адресная строка изменилась

  • мы приходим сновапосмотреть, что случилось с протоколом http

  • На картинке мы видим два кода состояния, один из них 302. Один 200.Код состояния 302 представляет собой временное перенаправление в протоколе http.. Например:Я пошел в Дисциплинарную комиссию и сказал: дайте мне бланк на увольнение, я хочу домой. В Дисциплинарном комитете мне сказали: у меня здесь нет бланка на отпуск, идите к вожатому.. Оглянитесь назад, когда я посетил Sevlet222: я искал Servlet222, и Servlet222 сказал браузеру: у меня нет нужного вам ресурса, нужный вам ресурс находится на странице index.jsp, вы можете найти его самостоятельно.
  • легко увидетьПо перенаправлению кода 302 состояния 302 и реализации адреса прыжка. Так,Мы можем установить заголовок сообщения http для достижения перенаправления и перехода

        //设置状态码是302
        response.setStatus(302);

        //HttpServletResponse把常用的状态码封装成静态常量了,所以我们可以使用SC_MOVED_TEMPORARILY代表着302
        response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);

        //跳转的地址是index.jsp页面
        response.setHeader("Location", "/zhongfucheng/index.jsp");

  • На самом деле метод sendRedirect() должен инкапсулировать setStatus() и setHeader()., принцип setStatus() и setHeader()

Детали getWriter и getOutputStream

  1. Два метода getWriter() и getOutputStream() не могут быть вызваны. При одновременном вызове произойдет исключение
  2. Программа сервлета для объекта ServletOutputStream или PrintWriterЗаписанные данные будут получены из ответа механизмом сервлета, который будет использовать данные в качестве тела ответного сообщения, а затем объединит их со строкой состояния ответа и заголовками ответа и выведет их клиенту..
  3. СервлетПосле завершения метода serice() [то есть после завершения doPost() или doGet()], обработчик сервлета проверит, вызывал ли объект выходного потока, возвращаемый методом getWriter или getOutputStream, метод close,Если нет, механизм сервлета вызовет метод close, чтобы закрыть объект выходного потока.

Если в статье есть ошибки, пожалуйста, исправьте меня и поделитесь друг с другом. Студенты, которые привыкли читать технические статьи о WeChat, могут обратить внимание на публичный аккаунт WeChat: Java3y.