• 图片服务器(2)


    如果服务器收到的是doGet请求,那么会调用HttpServlet的doGet方法

    如果服务器收到的是doPOST请求,那么会进行调用HttpServlet的doPOST方法

    1)封装是一种有效的管理复杂程序的手段,让类的使用者不需要关注类具体实现细节,让使用者降低学习和使用成本,但是还是需要关注这个对象是一个啥样的类型;

    但是多态,是封装的更近一步,使用者不光不需要知道类的具体实现是啥,也不需要关注这个对象的类型是什么,使用成本进一步降低,让复杂程序再次降低,多态尤其是在一些框架实现上面,创建的是ImageServlet,我们自己所写的doGet方法,其实本质上是调用的HttpServlet的doGet方法,此时就发生了多态,发生了向上转型,多态在框架实现上特别有用;

    List list=new ArrayList<>();

    list.add();就不需要进行关注List具体引用的对象类型是什么了,只需要有一个add方法

    2)HttpServletRequest req,这代表请求,这里面包含了方法,url,各种header头,还有body

    3)HttpServletResponse resp,这代表响应,里面包含了状态码,各种header,还有body

    4)Servlet里面没有main方法,而是依靠Tomact来进行自动调用到Servlet的代码,也就是说main方法在Tomact里面

    5)Tomact启动的时候要绑定端口号8080,之后进入到主循环

    在主循环里面调用accept方法,获取到当前请求的链接

    5.1)accept是一个阻塞的方法,当程序进行调用的时候,程序就不会向下走了,直到客户端给你发了请求,向你建立链接,此时accept才会返回;

    5.2)读取客户端发送的数据,也就是字符串,要把这个字符串按照HTTP协议进行解析;

    5.3)解析出来的HTTP请求的方法和URL之后,要找到对应的HttpServlet,并执行DoXXX方法

    Tomact中的Servlet是怎么工作的呢?

    Tomact会自动将我们打好的war包,解压成一个特定的文件目录;

    1)Tomact根据url来进行查找映射关系表,找到对应的ImageServlet类;

    2)Tomact根据GET方法,决定给ImageServlet创建一个HttpServletRequest对象

    并调用里面的doGET方法;

    3)执行doGet方法,向resp对象里面写了一个hello;

    4)Tomact构造resp对象,我们根据这个对象生成HTTP响应报文,再通过socket发回给浏览器

    下面我们再写一段代码来进行演示一下:

    1)启动Tomact服务器:Socket.start();

    2)创建socket对象ServerSocket socket

    3)通过Socket绑定IP地址和端口号:socket.bind(服务器的IP和端口号)

    4)读取客户端发送过来的数据:

    1. Socket socket=new Socket()
    2. socket.bind(端口号)
    3. while(true)
    4. {
    5. Socket newSocket=socket.accept();//有请求就进行创建,没有请求就进行阻塞等待
    6. //1循环读取数据(客户端发送过来的数据,读到的数据相当于是一个完整的HTTP请求
    7. 按照TCP字节流来进行读取
    8. Byte[] inputBuffer=new Socket.read();
    9. //2.我们进行解析HTTP请求的格式的数据,也就是读取字符串,解析信息,
    10. //我们根据解析到的Http格式的数据解析成ServletReequest对象
    11. HttpServletRequest req=parse(inputBuffer);
    12. }

    Byte[] inputBuffer=new Socket.read()相当于是去掉里面的TCP报头,读取到TCP数据包

    5)现在开始就要进行用户调用自己写的代码了(ImageServlet),下面的代码也在循环里面

    1. 7)HttpServlet httpServlet=new ImageServlet(req.getURL());
    2. //根据webServlet中的注解创建一个HttpServlet,这里面就发生了多态
    3. 父类引用引用子类对象,其实本质上这个httpServlet引用的是ImageServlet
    4. 调用到用户自己写的代码
    5. 8)if(req.getMethod().equals("GET"){
    6. httpServlet.doGet(req,resp);
    7. }else if(req.getMethod().equals("POST")
    8. {
    9. httpServlet.doPost(req,resp);
    10. }else if.....
    11. 9)我们执行完上面的方法之后,我们就要把resp对象转化成字符串,写回到socket之中
    12. newSocket.write(resp.ToString)
    13. }

    1)HttpServletResponse对象就是存储我们的doGet方法生成的结果

    2)那么此时这个HttpServletRequest对象就包含了一些属性,里面就包含了请求中的所有信息,比如说方法:GET/POST,url:/image,各种Header头:通过map进行组织(Cookie,Session,ContentType),各种参数:什么HTTP/1.1,请求的queryString中的键值对

    body:请求格式的数据

    1)Servlet从本质上来说就是一个代码编程框架,当前已经有很多现成的代码了,我们是不需要用户来进行手写所有的代码,用户只需要写其中的一小部分,就可以完成整个工作,像咱们的HTTP服务器是怎么绑定端口的,怎么读取Http请求解析成HttpServletRequest对象,咱们是不需要进行关心的

    2)Servlet的核心工作就是说创建一个Servlet类,这个类里面完成如何根据Http请求来进行计算Http响应

    3)我们打好的war包里面包含了.class文件,还包括web开发中涉及到的html的其他文件,还有以来的一些第三方库war 包是 JavaWeb 程序打的包,war 包里面包括写的代码编译成的 class 文件,依赖的包,配置文件,所有的网站页面, 包括 html,jsp,还有第三方库的jar包

    4)部署过程:使用maven打一个war包,把war包拷贝到Tomact的webapp目录里面

    咱们现在写的代码片段:

    req对象里面包含了请求中的所有信息,resp对象要生成的结果就要放到里面去,当前我们所写的doGET方法就是根据请求生成响应

    编码出错:汉字编码的典型格式有两种:

    1)GBK:浏览器默认按照GBK来进行解析,按照操作操作系统的默认编码来进行解析,Windows简体中文默认GBK;

    2)UTF8:(IDEA创建的文件默认);

    我们解决的方法就是说让浏览器按照utf-8的格式进行解析,让浏览器和IDEA的默认解析编码的格式一致

    我们想要上传文件,解析文件,就要用到这个第三方库:fileupload

    1. <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
    2. <dependency>
    3. <groupId>commons-fileupload</groupId>
    4. <artifactId>commons-fileupload</artifactId>
    5. <version>1.4</version>
    6. </dependency>

    1.执行图片上传操作:

    在进行写代码的过程中,我们一定要注意:

    1)数据库是否成功的插入了图片,咱们的文件内容是否成功写入到了磁盘上面

    2)只能使用POST请求发送图片,后端只能使用用 FileItemFactory factory=new DiskFileItemFactory();
    ServletFileUpload upload=new ServletFileUpload(factory);解析

      list= upload.parseRequest(req);//这个list中的元素就是存放着每张图片的属性,每一张图片都对应着一个属性,这些属性都是从我们的body中进行获取的
    1. 我认为这个list应该是这样的一个数组:
    2. list:
    3. {
    4. [
    5. 图片1的名字属性
    6. 图片1的大小属性
    7. 图片1的类型属性
    8. ],
    9. [
    10. 图片1的名字属性
    11. 图片1的大小属性
    12. 图片1的类型属性
    13. ]
    14. }
    15. 但是当前我们一次只上传的一张图片,所以我们只需要list.get(0),就可以进行获取到我们的上传的唯一一张图片了

    3)咱们保存的图片路径就是(所有图片的根路径)+文件名后缀

    代码步骤:

    1.从请求中获取图片的属性信息,存入到数据库里面和磁盘数据(Image类)

    总体大致步骤:

    1)获取图片的属性信息,并且存入到数据库里面

    2)获取到图片的内容信息,并且存入到磁盘文件里面

    3)给客户端返回一个结果的数据

    1. 1.获取图片的属性信息,存入到数据库里面(Image类)
    2. 1.1我们需要创建一个factory对象和upload对象,这里是为了或者去图片属性做的准备工作
    3. ObjectMapper objectMapper=new ObjectMapper();
    4. FileItemFactory factory=new DiskFileItemFactory();
    5. ServletFileUpload upload=new ServletFileUpload(factory);
    6. //上面的写法都是固定的
    7. 1.2我们通过upload对象的parseRequest()方法来进行解析请求
    8. (这个方法主要是用来解析Http中的req请求中奇怪的body内容)
    9. 最终返回一个List数组
    10. //理论上来说一个HTTP请求支持同时上传多个文件,这里面就上传一个
    11. List list=null;
    12. try {
    13. 上面的这个list中的元素就是存放着每张图片的属性,每一张图片都对应着一个属性
    14. 这些属性都是从我们的body中进行获取的
    15. list= upload.parseRequest(req);
    16. System.out.println(list);
    17. } catch (FileUploadException e) {
    18. 1.4出现异常说明解析出错,我们就可以告诉客户端具体的错误是啥,图片解析失败直接返回
    19. e.printStackTrace();
    20. resp.setContentType("applictaion/json;charset=utf-8");
    21. Reason reason=new Reason();
    22. reason.OK=1;
    23. reason.reason=e.getMessage()+"请求解析失败";
    24. String html= objectMapper.writeValueAsString(reason);
    25. resp.getWriter().write(html+"list是"+list);
    26. return;
    27. }

    1)我们调用upload中的parseRequest(req)方法就可以解析POST方法中的解析body数据的内容,我们最终返回的是一个list数组,数组里面就包含了一个个的FileItem对象

    2)这里面的FileItem就代表一个上传的文件对象,里面就包含着图片的属性信息 

    1. 1.3.我们把FileItem中的属性进行提取出来,转换成Image对象,才能存取到数据库里面,当前只考虑上传一张图片的情况,如果想要处理多张就需要进行循环处理
    2. FileItem fileItem=list.get(0);
    3. Image image=new Image();
    4. 1.2.1.给image对象封装成一些属性,首先我们来进行配置
    5. image.setImageName(fileItem.getName());
    6. image.setImageSize((int)fileItem.getSize());
    7. image.setContentType(fileItem.getContentType());
    8. 1.2.3.上面的这些属性都是在我们的请求报文格式中都是存在的
    9. 比如说文件名,文件大小,文件的类型,但是下面的日期请求body中没有,我们就需要进行指定了
    10. 比如说yyMMDD-->20220218,yy表示年份,MM表示月份,dd就表示日期
    11. SimpleDateFormat simpleDataFormat=new SimpleDateFormat("yyyyMMdd");
    12. image.setImageTime(simpleDataFormat.format(new Date()));
    13. //获取当前时间,变成格式化日期
    14. 1.2.3.我们需要进行设置文件的在磁盘上面的存放路径,下面会默认生成在Tomact的bin目录下面
    15. image.setContentPath("./image/"+image.getImageName());
    16. image.setMd5("11223344");
    17. 1.2.4成功的把数据库属性信息存储到数据库里面,其实本质上插入的是一个一个的Image对象
    18. OperateImage operateImage=new OperateImage();
    19. try {
    20. operateImage.InsertImage(image);
    21. } catch (SQLException throwables) {
    22. throwables.printStackTrace();
    23. } catch (JavaOperateMysql javaOperateMysql) {
    24. javaOperateMysql.printStackTrace();
    25. }

     1)我们通过list.get(0)就可以获取到这个fileItem对象,这个对象里面就包含了我们进行上传的图片的属性,我们就可以创建一个Image对象,根据fileItem属性配置Image对象,插入到数据库里面

    2)但是我们一定要注意,我们的fileItem这个对象的属性只有我们请求中的body格式的数据的属性,对于上传时间,是没有这样的属性的,所以我们要进行获取当前时间:     

    3)SimpleDateFormat simpleDataFormat=new SimpleDateFormat("yyyyMMdd");
    image.setImageTime(simpleDataFormat.format(new Date()));//获取当前时间,变成格式化日期

    1. 2.获取到图片的内容信息,并且写入到磁盘文件里面(文件的正是内容,二进制内容)
    2. File file=new File(image.getContentPath());
    3. try {
    4. fileItem.write(file);
    5. } catch (Exception e) {
    6. e.printStackTrace();
    7. //写入磁盘失败给前端传递一个信息
    8. Reason reason=new Reason();
    9. reason.OK=2;
    10. reason.reason=e.getMessage();
    11. String html= objectMapper.writeValueAsString(reason);
    12. resp.getWriter().write(html+"文件写入磁盘失败");
    13. return;
    14. }
    15. System.out.println("文件写入磁盘成功");
    16. 给客户端返回一个结果数据,做一个反馈
    17. Reason reason=new Reason();
    18. reason.OK=0;
    19. reason.reason="上传图片成功";
    20. String html=objectMapper.writeValueAsString(reason);
    21. resp.getWriter().write(html);

    我们现在开始进行测试我们的代码:

    我们在浏览器上面直接访问路由地址,然后我们上传文件,就可以发现下面的返回结果

    1)但是现在还是出现了一个问题,我们按照原有的设定,图片存储的路径就是"./image/文件名",但是如果说两张图片,文件内容不同上传失败的情况,但是文件名相同,那么就会出现上传失败,后面需要访问图片文件的时候,直接通过文件路径通过读文件的方式来进行读取数据

    2)所以说我们应该让每一次上传图片的对应的路径都不相同(在路径中就设置一个一个UUID),或者通过时间戳的方式来进行区分相同的名字

    3)将图片从linux上传输到windows上面sz+1.png

    2.第二组API:我们主要是通过doGet请求来获取到多有图片的信息和指定图片的信息(两种操作)

    我们就可以通过请求中的URL中是否带有ImageID来进行区分

    1)我们获取到所有的图片信息:

    1. package API;
    2. import Dao.Image;
    3. import Dao.OperateImage;
    4. import com.fasterxml.jackson.databind.ObjectMapper;
    5. import javax.servlet.ServletException;
    6. import javax.servlet.annotation.WebServlet;
    7. import javax.servlet.http.HttpServlet;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import java.io.IOException;
    11. import java.sql.SQLException;
    12. import java.util.List;
    13. @WebServlet("/GetImageAll")
    14. public class ChectAllImageServlet extends HttpServlet {
    15. public class Response{
    16. public int OK;
    17. public String reason;
    18. }
    19. @Override
    20. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    21. resp.getWriter().write("application/json;charset=utf-8");
    22. ObjectMapper objectMapper=new ObjectMapper();
    23. //1.进行创建一个OperateImage对象,我们进行数据库的查询操作
    24. OperateImage operateImage=new OperateImage();
    25. //2.把查询到的结果转化成Json格式的字符串,返回给前端
    26. try {
    27. List list= operateImage.SelectAll();
    28. String html=objectMapper.writeValueAsString(list);
    29. resp.getWriter().write(html);
    30. } catch (SQLException throwables) {
    31. throwables.printStackTrace();
    32. Response response=new Response();
    33. response.OK=3;
    34. response.reason="查询的时候所有文件内容SQL语句执行失败";
    35. String html= objectMapper.writeValueAsString(response);
    36. resp.getWriter().write(html);
    37. }
    38. }
    39. }

    2)我们进行获取到了指定的图片信息:

    1. package API;
    2. import Dao.Image;
    3. import Dao.OperateImage;
    4. import com.fasterxml.jackson.databind.ObjectMapper;
    5. import javax.servlet.ServletException;
    6. import javax.servlet.annotation.WebServlet;
    7. import javax.servlet.http.HttpServlet;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import java.io.IOException;
    11. import java.sql.SQLException;
    12. @WebServlet("/GetImageOne")
    13. public class CheckOneImageServlet extends HttpServlet {
    14. public class Response{
    15. public int OK;
    16. public String reason;
    17. }
    18. @Override
    19. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    20. resp.setContentType("application/json;charset=utf-8");
    21. //1.获取到图片ID
    22. String ImageID=req.getParameter("ImageID");
    23. ObjectMapper objectMapper=new ObjectMapper();
    24. OperateImage operateImage=new OperateImage();
    25. //2.判断获取到的图片ID是否为空,如果是空,那么直接返回
    26. if(ImageID.equals("")||ImageID==null)
    27. {
    28. Response response=new Response();
    29. response.reason="当前请求中的ImageID缺失,说明我们的前端传递的参数有问题";
    30. }
    31. //3.从数据库中进行查询
    32. Image image = null;
    33. try {
    34. image= operateImage.SelectOne(Integer.parseInt(ImageID));
    35. } catch (SQLException throwables) {
    36. throwables.printStackTrace();
    37. Response response=new Response();
    38. response.reason="查询指定图片的数据库操作查询失败"+throwables.getMessage();
    39. String html= objectMapper.writeValueAsString(response);
    40. resp.getWriter().write(html);
    41. return;
    42. }
    43. if(image==null||image.equals("")){
    44. Response response=new Response();
    45. response.reason="当前我们无法通过前端传递的ImageID来进行查找对应的Image";
    46. String html= objectMapper.writeValueAsString(response);
    47. resp.getWriter().write(html);
    48. }
    49. String html= objectMapper.writeValueAsString(image);
    50. resp.getWriter().write(html);
    51. }
    52. }

    3)我们进行删除操作:

    1. package API;
    2. import Dao.Image;
    3. import Dao.OperateImage;
    4. import com.fasterxml.jackson.databind.ObjectMapper;
    5. import javax.servlet.ServletException;
    6. import javax.servlet.annotation.WebServlet;
    7. import javax.servlet.http.HttpServlet;
    8. import javax.servlet.http.HttpServletRequest;
    9. import javax.servlet.http.HttpServletResponse;
    10. import java.io.File;
    11. import java.io.IOException;
    12. import java.sql.SQLException;
    13. @WebServlet("/DeleteImage")
    14. public class DeleteImageServlet extends HttpServlet {
    15. static class Response{
    16. public int OK;
    17. public String response;
    18. }
    19. @Override
    20. protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    21. ObjectMapper objectMapper=new ObjectMapper();
    22. resp.setContentType("application/json;charset=utf-8");
    23. //1.获取到请求中的ImageID
    24. String ImageID=req.getParameter("ImageID");
    25. if(ImageID==null||ImageID.equals(""))
    26. {
    27. Response response=new Response();
    28. response.OK=4;
    29. response.response="当前您进行传递的ImageID为空,我们无法进行删除对应的照片";
    30. String html= objectMapper.writeValueAsString(response);
    31. resp.getWriter().write(html);
    32. }
    33. //2.创建OperateImage对象,查看该图片对象对应的相关属性(查看相关属性主要是为了直到这个跟图片对应的文件路径)
    34. OperateImage operateImage=new OperateImage();
    35. try {
    36. Image image=operateImage.SelectOne(Integer.parseInt(ImageID));
    37. if(image==null||image.equals(""))
    38. {
    39. Response response=new Response();
    40. response.OK=5;
    41. response.response="数据库中没有ImageID对应的图片信息,我们不进行删除操作也是可以的"+ImageID;
    42. String html= objectMapper.writeValueAsString(response);
    43. resp.getWriter().write(html);
    44. return;
    45. }
    46. //3.删除数据库中的记录
    47. operateImage.Delete(Integer.parseInt(ImageID));
    48. //4.删除本地磁盘文件
    49. File file=new File((image.getContentPath()));
    50. file.delete();
    51. Response response=new Response();
    52. response.OK=0;
    53. response.response="删除指定图片成功ImageID是"+ImageID;
    54. String html=objectMapper.writeValueAsString(response);
    55. resp.getWriter().write(html);
    56. } catch (SQLException throwables) {
    57. throwables.printStackTrace();
    58. }
    59. }
    60. }

  • 相关阅读:
    【3D目标检测】Monocular 3D Object Detection with Pseudo-LiDAR Point Cloud
    DDR SDRAM 学习笔记
    网络传输中的重要参数-简单的网络画像
    Net 如何获取私有属性
    【2017NOIP普及组】T3:棋盘 试题解析
    数据结构--队列与循环队列的实现
    Go语言将string解析为time.Time时两种常见报错
    Nginx 压测方法论和性能指标
    对Transformer中的Attention(注意力机制)的一点点探索
    【二叉树-中等】1104. 二叉树寻路
  • 原文地址:https://blog.csdn.net/weixin_61518137/article/details/126858888