如果服务器收到的是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(); } } }