零基础编写图片服务器(2)

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

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

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

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

List<Images> 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)读取客户端发送过来的数据:

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

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

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

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

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

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

1.执行图片上传操作:

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

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

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

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

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

代码步骤:

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

总体大致步骤:

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

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

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

 1.获取图片的属性信息,存入到数据库里面(Image类)
 1.1我们需要创建一个factory对象和upload对象,这里是为了或者去图片属性做的准备工作
        ObjectMapper objectMapper=new ObjectMapper();
        FileItemFactory factory=new DiskFileItemFactory();
        ServletFileUpload upload=new ServletFileUpload(factory);
        //上面的写法都是固定的

1.2我们通过upload对象的parseRequest()方法来进行解析请求
(这个方法主要是用来解析Http中的req请求中奇怪的body内容)
最终返回一个List<FileItem>数组
//理论上来说一个HTTP请求支持同时上传多个文件,这里面就上传一个
        List<FileItem> list=null;
        try {
上面的这个list中的元素就是存放着每张图片的属性,每一张图片都对应着一个属性
这些属性都是从我们的body中进行获取的
            list= upload.parseRequest(req);
            System.out.println(list);
        } catch (FileUploadException e) {
1.4出现异常说明解析出错,我们就可以告诉客户端具体的错误是啥,图片解析失败直接返回
            e.printStackTrace();
            resp.setContentType("applictaion/json;charset=utf-8");
            Reason reason=new Reason();
            reason.OK=1;
            reason.reason=e.getMessage()+"请求解析失败";
            String html= objectMapper.writeValueAsString(reason);
            resp.getWriter().write(html+"list是"+list);
            return;
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

package API;
import Dao.Image;
import Dao.OperateImage;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List;
@WebServlet("/GetImageAll")
public class ChectAllImageServlet extends HttpServlet {
    public class Response{
        public int OK;
        public String reason;
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      resp.getWriter().write("application/json;charset=utf-8");
        ObjectMapper objectMapper=new ObjectMapper();
      //1.进行创建一个OperateImage对象,我们进行数据库的查询操作
        OperateImage operateImage=new OperateImage();
      //2.把查询到的结果转化成Json格式的字符串,返回给前端
        try {
            List<Image> list= operateImage.SelectAll();
            String html=objectMapper.writeValueAsString(list);
            resp.getWriter().write(html);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
             Response response=new Response();
             response.OK=3;
             response.reason="查询的时候所有文件内容SQL语句执行失败";
             String html= objectMapper.writeValueAsString(response);
            resp.getWriter().write(html);
        }
    }
}

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

package API;
import Dao.Image;
import Dao.OperateImage;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.SQLException;
@WebServlet("/GetImageOne")
public class CheckOneImageServlet extends HttpServlet {
    public class Response{
        public int OK;
        public String reason;
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        //1.获取到图片ID
        String ImageID=req.getParameter("ImageID");
        ObjectMapper objectMapper=new ObjectMapper();
        OperateImage operateImage=new OperateImage();
        //2.判断获取到的图片ID是否为空,如果是空,那么直接返回
        if(ImageID.equals("")||ImageID==null)
        {
            Response response=new Response();
            response.reason="当前请求中的ImageID缺失,说明我们的前端传递的参数有问题";
        }
        //3.从数据库中进行查询
        Image image = null;
        try {
             image= operateImage.SelectOne(Integer.parseInt(ImageID));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
            Response response=new Response();
            response.reason="查询指定图片的数据库操作查询失败"+throwables.getMessage();
            String html= objectMapper.writeValueAsString(response);
            resp.getWriter().write(html);
            return;
        }
        if(image==null||image.equals("")){
            Response response=new Response();
            response.reason="当前我们无法通过前端传递的ImageID来进行查找对应的Image";
            String html= objectMapper.writeValueAsString(response);
            resp.getWriter().write(html);
        }
        String html= objectMapper.writeValueAsString(image);
        resp.getWriter().write(html);
    }
}

3)我们进行删除操作:

package API;

import Dao.Image;
import Dao.OperateImage;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.sql.SQLException;

@WebServlet("/DeleteImage")
public class DeleteImageServlet extends HttpServlet {
    static class Response{
        public int OK;
        public String response;
    }
    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ObjectMapper objectMapper=new ObjectMapper();
        resp.setContentType("application/json;charset=utf-8");
        //1.获取到请求中的ImageID
        String ImageID=req.getParameter("ImageID");
        if(ImageID==null||ImageID.equals(""))
        {
            Response response=new Response();
            response.OK=4;
            response.response="当前您进行传递的ImageID为空,我们无法进行删除对应的照片";
            String html= objectMapper.writeValueAsString(response);
            resp.getWriter().write(html);
        }
        //2.创建OperateImage对象,查看该图片对象对应的相关属性(查看相关属性主要是为了直到这个跟图片对应的文件路径)
        OperateImage operateImage=new OperateImage();
        try {
            Image image=operateImage.SelectOne(Integer.parseInt(ImageID));
            if(image==null||image.equals(""))
            {
                Response response=new Response();
                response.OK=5;
                response.response="数据库中没有ImageID对应的图片信息,我们不进行删除操作也是可以的"+ImageID;
                String html= objectMapper.writeValueAsString(response);
                resp.getWriter().write(html);
                return;
            }
            //3.删除数据库中的记录
            operateImage.Delete(Integer.parseInt(ImageID));
            //4.删除本地磁盘文件
            File file=new File((image.getContentPath()));
            file.delete();
            Response response=new Response();
            response.OK=0;
            response.response="删除指定图片成功ImageID是"+ImageID;
            String html=objectMapper.writeValueAsString(response);
            resp.getWriter().write(html);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值