日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發(fā)布時間:2023/12/8 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 零基础编写图片服务器(1) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1)在我們真正進(jìn)行WEB開發(fā)的時候,編寫代碼之前,我們都要做兩件非常重要的設(shè)計:數(shù)據(jù)庫設(shè)計+前后端交互API接口的設(shè)計+JDBC操作+WEB服務(wù)器開發(fā)能力,我們還要實(shí)現(xiàn)一個簡單的頁面來進(jìn)行展示當(dāng)前的圖片

2)學(xué)習(xí)測試服務(wù)器---->PostMan

1.項(xiàng)目背景:首先它是一個服務(wù)器(圖床)

1)核心功能:上傳圖片,展示圖片

2)我們通常會寫博客,githup,可能我們也是會穿插圖片或者其他資源,我們寫博客的時候,插入的圖片,本質(zhì)上就是一個url,這個鏈接所對應(yīng)的圖片資源在另一個服務(wù)器上面,本質(zhì)上CSDN已經(jīng)內(nèi)置了這個圖片服務(wù)器功能

3)當(dāng)我們在瀏覽器上面輸入圖片的時候,我們點(diǎn)擊這個圖片,復(fù)制鏈接地址,然后再來打開一個瀏覽器的窗口,輸入剛才的這個鏈接地址,展示搜索結(jié)果,我們就可以看到這個圖片了

2.核心知識點(diǎn):

1)簡單的Web服務(wù)器(HTTP服務(wù)器)設(shè)計開發(fā)能力(Servlet)

2)Servlet是Tomact這個服務(wù)器提供的一組編程接口,我們就可以開發(fā)出我們自己所實(shí)現(xiàn)的一套邏輯,這一套邏輯我們就可以部署到Tomact里面,就可以完成一個我們自己的服務(wù)器的搭建

3)使用數(shù)據(jù)庫進(jìn)行存儲

4)學(xué)會設(shè)數(shù)據(jù)庫設(shè)計,根據(jù)實(shí)際場景設(shè)計數(shù)據(jù)庫表結(jié)構(gòu)

5)前后端接口的設(shè)計,前后端交互的API的設(shè)計

6)認(rèn)識JSON數(shù)據(jù)格式,使用Gson這個庫來進(jìn)行操作JSON

7)學(xué)習(xí)測試一個服務(wù)器(postman),使用HTML,CSS,javascript來進(jìn)行構(gòu)建一個簡單的網(wǎng)頁

3.服務(wù)器設(shè)計和數(shù)據(jù)庫設(shè)計

1)mysql -uroot連接數(shù)據(jù)庫,就是啟動了MYSQL客戶端,我們之前安裝數(shù)據(jù)庫,即安裝了服務(wù)器又安裝了客戶端(命令行程序),是同過網(wǎng)絡(luò)來進(jìn)行通信的

2)MYSQL服務(wù)器就是我們的本體,在這個服務(wù)器里面包含著數(shù)據(jù)庫和表;

3)MariaDB和MYSQL有什么關(guān)系?

4)創(chuàng)建表結(jié)構(gòu):

描述圖片相關(guān)的內(nèi)容(屬性信息)

1)ImageID 圖片ID primary key auto_increment----圖片的唯一身份標(biāo)識

2)ImageName varchar(50)------圖片的名字

3)ImageSize int------圖片的大小

4)ImageTime varchar(50)------圖片的上傳時間

5)ContentType varchar(50)---->image/jpg

(ContentType(HTTP數(shù)據(jù)類型)=image/png)-----表示圖片類型

6)ContentPath varchar(50)--------路徑,服務(wù)器本地的目錄

7)md5 varchar(1024)------校驗(yàn)和(在應(yīng)用層進(jìn)行校驗(yàn))

咱們的數(shù)據(jù)庫中存儲的是圖片的屬性和路徑;

圖片正文,是以文件的形式直接存儲在磁盤里面的,數(shù)據(jù)庫中的一個Contentpath就是對應(yīng)咱們磁盤上面的文件

md5:字符串哈希算法,密碼學(xué)領(lǐng)域也能用到

1)圖片的MD5校驗(yàn)和,應(yīng)用層進(jìn)行數(shù)據(jù)校驗(yàn),通過一個更短的字符串來進(jìn)行驗(yàn)證整體數(shù)據(jù)是否正確,短的字符串是根據(jù)源字符串的內(nèi)容按照一定的規(guī)則來計算出來的;

2)src循環(huán)冗余校驗(yàn)算法

3)哈希算法就是把key經(jīng)過一系列的數(shù)學(xué)變換,得到一個整數(shù),對應(yīng)到數(shù)組下標(biāo)上面,把hello字符串計算出一個哈希值(123456),把這個哈希值去%數(shù)組的長度從而得到數(shù)組下標(biāo)

4.服務(wù)器API設(shè)計:

JSON是一種數(shù)據(jù)組織的格式,格式是鍵值對的結(jié)構(gòu),gson既可以解析哈希表也是可以進(jìn)行解析類的,還可以解析數(shù)組;

第一種用法:把哈希表轉(zhuǎn)化成JSON格式的數(shù)據(jù)

對于對象來說,轉(zhuǎn)化成JSON格式的數(shù)據(jù)鍵就是字段名,Value就是這個字段對應(yīng)的值

引入2.8.6的庫 import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.HashMap; public class TestJson {public static void main(String[] args) {HashMap<String,Object> hashMap=new HashMap<>();//1.創(chuàng)建hashmaphashMap.put("name","曹操");hashMap.put("代碼大神","李佳偉");//2創(chuàng)建Json對象Gson gson=new GsonBuilder().create();//3.使用ToGson方法轉(zhuǎn)成字符串String str= gson.toJson(hashMap);//里面的參數(shù)也可以是一個對象System.out.println(str);} }

第二種用法:使用數(shù)組

import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class TestJson {static class Student{public String username;public int age;public String password;}public static void main(String[] args) {Student student1=new Student();student1.age=12;student1.username="李佳偉";student1.password="12503487";Student student2=new Student();student2.age=12;student2.username="周云剛";student2.password="778896";List<Student> list=new ArrayList<>();list.add(student1);list.add(student2);Gson gson=new GsonBuilder().create();String str= gson.toJson(list);System.out.println(str);} }

回顧:文件上傳操作在HTML中是如何完成的

1)我們直接在前端使用form表單

<form action="upload" method="POST" enctype="multipart/form-data"><input type="file" name="MyImage"><input type="submit" value="提交圖片"></form> 1)這里面的ID就表示唯一的身份標(biāo)識 2)action:提交圖片的時候,產(chǎn)生的HTTP請求產(chǎn)生的Path是怎么樣的,url 3)method:GET方法上傳還是POST方法上傳 4)enctype:表示請求的格式,文件的傳輸格式

我們開始正式設(shè)計前后端進(jìn)行交互的API:HTTP協(xié)議具體要構(gòu)造成什么樣子

1)新增圖片:

請求: POST/Image ContentType:multipart/form-data;正文內(nèi)容:包含圖片自身的一些信息,圖片正文的二進(jìn)制內(nèi)容響應(yīng): 1)上傳成功的情況: HTTP/1.1 200 OK {OK:"1",reason:"上傳成功" } 2)上傳失敗的情況: HTTP/1.1 200 OK {OK:"0",reason:"上傳圖片失敗" }

2)查看所有圖片信息(數(shù)據(jù)庫存放的屬性信息)

請求: GET/Image響應(yīng): HTTP/1.1 200 OK [{ImageID:1,ImageName:"代碼.png",ImageSize:1000,ImageTime:"2022/12/2",ContentType:"image/png",ContentPath:"./data/1.png",md5:"1122334455"},{ImageID:2,ImageName:"板書.png",ImageSize:1050,ImageTime:"2022/10/2",ContentType:"image1/png",ContentPath:"./data/2.png",md5:"778896"} ] 獲取失敗: HTTP/1.1 200 OK []

3)查看指定圖片信息

請求: GET/Image?ImageID=7 響應(yīng):HTTP/1.1 200 OK {ImageID:1,ImageName:"代碼.png",ImageSize:1000,ImageTime:"2022/12/2",ContentType:"image/png",ContentPath:"./data/1.png",md5:"1122334455"} 響應(yīng)失敗: HTTP/1.1 200 OK {OK:"0",reason:"失敗的原因" }

4)刪除操作(刪除指定圖片)

請求: DELETE/Image?ImageID=具體的圖片ID 響應(yīng): HTTP/1.1 200 OK {OK:"200",reason:"" } 響應(yīng)失敗: HTTP/1.1 200 OK { OK:"200",reason:"出錯原因", }

6)查看指定圖片內(nèi)容(咱們的圖片內(nèi)容到底展示的是小貓小狗,還是其他呢?)

請求:GET/ImageShow?ImageID=1響應(yīng):HTTP/1.1 200 OK ContentType:image/jpg[圖片的二進(jìn)制內(nèi)容]返回錯誤: HTTP/1.1 200 OK {OK:"200",reason:"出錯的原因" }

我們總共拆分成了兩個Servlet,一個路徑請求對應(yīng)著一個Servlet

源碼開發(fā):

一:封裝獲取到數(shù)據(jù)庫連接操作

create table Image(ImageID int primary key auto_increment,ImageName varchar(100),ImageSize int,ImageTime dateTime,ContentType varchar(50),ContentPath varchar(100),md5 varchar(100)); 此時咱們的數(shù)據(jù)庫是在linux上面進(jìn)行運(yùn)行的,咱們要在數(shù)據(jù)庫中進(jìn)行創(chuàng)建表 package Dao; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class ConnectionMysql {private static volatile DataSource dataSource=null;private static String url="jdbc:mysql://127.0.0.1:3306/picturemaven?characterEncoding=utf-8&userSSL=true";private static String username="root";private static String password="12503487";private static DataSource GetDataSource(){if(dataSource==null){synchronized(Object.class){if(dataSource==null){dataSource=new MysqlDataSource();((MysqlDataSource)dataSource).setPassword(password);((MysqlDataSource)dataSource).setUser(username);((MysqlDataSource)dataSource).setURL(url);}}}return dataSource;}public static Connection GetConnection() throws SQLException {return GetDataSource().getConnection();}public static void Close(ResultSet resultSet, PreparedStatement preparedStatement,Connection connection) throws SQLException {if(resultSet!=null){resultSet.close();}if(preparedStatement!=null){preparedStatement.close();}if(connection!=null){connection.close();}} }

1)多個線程同時操作一個數(shù)據(jù)的時候,可能會發(fā)生線程安全問題

1.1)當(dāng)我們進(jìn)行創(chuàng)建datasource實(shí)例的時候,進(jìn)入if語句之后,可能就是說第一個線程在進(jìn)行new datasource()實(shí)例的時候(datasource實(shí)例,馬上就要進(jìn)行創(chuàng)建了),可能線程2在這個時候會搶占CPU,到就緒隊(duì)列上面執(zhí)行;

1.2)當(dāng)?shù)诙€線程進(jìn)行讀取(進(jìn)入到if語句判斷里面)發(fā)現(xiàn)datasource是空(此時線程1還沒有創(chuàng)建DataSource實(shí)例,就被線程2搶走了,線程2會立即執(zhí)行創(chuàng)建dataSource實(shí)例),就會創(chuàng)建第一份datasource實(shí)例,當(dāng)我們的線程1被調(diào)度上CPU執(zhí)行之后(if語句因?yàn)檎{(diào)度被線程2搶走之前已經(jīng)判斷為空了,PCB的上下文此時就會發(fā)生作用),又會進(jìn)行創(chuàng)建datasource對象,從而導(dǎo)致線程不安全問題

2)資源關(guān)閉順序一定要正確(后創(chuàng)建的先進(jìn)行釋放)

3)咱們的ctrl+alt+t surround功能是選中一部分代碼之后,在這個代碼外邊加上一些其他代碼

4)加上volatile關(guān)鍵字之后就可以防止線程1創(chuàng)建DataSource實(shí)例之后,線程2也想創(chuàng)建DataSource,無法感知線程1已經(jīng)創(chuàng)建了DataSource實(shí)例,還認(rèn)為DataSource為空呢,進(jìn)行外層if判斷的時候可能會導(dǎo)致判斷錯誤

這個程序會報錯,數(shù)據(jù)庫會無法連接?

二:封裝數(shù)據(jù)庫操作數(shù)據(jù)

受查異常:向上拋出或者是就地處理

出現(xiàn)異常之后的處理措施:

1)直接用catch進(jìn)行捕獲,里面直接打印信息調(diào)用棧

2)直接拋出異常,讓我們的程序進(jìn)行終止

3)監(jiān)控報警直接通知程序員,這個一般適用于服務(wù)器,我們就去專門寫一個程序,它是用來感知服務(wù)器是否出現(xiàn)了問題,一旦我們的程序發(fā)生了問題,那么直接發(fā)送短信/電話/微信(比如說充錢操作)

Java代碼封裝數(shù)據(jù)庫:

1)創(chuàng)建一個Image對象,對應(yīng)一個圖片對象(包括圖片的相關(guān)屬性),這一個類就對應(yīng)著一張數(shù)據(jù)庫的表(里面的path屬性就表示我們的圖片位置在我們的計算機(jī)硬盤上面的哪一個位置),咱們的數(shù)據(jù)庫只是存放圖片的屬性,而咱們具體的圖片內(nèi)容是存放在一個個的文件里面;

package Dao;public class Image {private int ImageID;private String ImageName;private int ImageSize;private String ImageTime;private String ConteneType;private String ContentPath;private String md5;public int getImageID() {return ImageID;}public void setImageID(int imageID) {ImageID = imageID;}public String getImageName() {return ImageName;}public void setImageName(String imageName) {ImageName = imageName;}public int getImageSize() {return ImageSize;}public void setImageSize(int imageSize) {ImageSize = imageSize;}public String getImageTime() {return ImageTime;}public void setImageTime(String imageTime) {ImageTime = imageTime;}public String getConteneType() {return ConteneType;}public void setConteneType(String conteneType) {ConteneType = conteneType;}public String getContentPath() {return ContentPath;}public void setContentPath(String contentPath) {ContentPath = contentPath;}public String getMd5() {return md5;}public void setMd5(String md5) {this.md5 = md5;}@Overridepublic String toString() {return "Image{" +"ImageID=" + ImageID +", ImageName='" + ImageName + '\'' +", ImageSize=" + ImageSize +", ImageTime='" + ImageTime + '\'' +", ConteneType='" + ConteneType + '\'' +", ContentPath='" + ContentPath + '\'' +", md5='" + md5 + '\'' +'}';} }

2)我們在進(jìn)行創(chuàng)建一個包叫做ImageDemo,在進(jìn)行創(chuàng)建一個類叫做OperateImage對象的管理器,我們希望借助這個類完成對對象的增刪改查

2.1)當(dāng)我們進(jìn)行新增一個Image對象的時候,實(shí)現(xiàn)這個方法的時候,我們在方法里面直接傳入一個Image對象,進(jìn)行插入數(shù)據(jù)庫里面

2.2)進(jìn)行查找的時候,我們要分成兩種情況,一種是查詢所有的圖片(List<Image>,一種是查找指定ID的圖片(Image)

2.3)刪除操作,是指定圖片的ID進(jìn)行刪除,ImageID:

package Dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class OperateImage {public void InsertImage(Image image) throws SQLException, JavaOperateMysql {//1與數(shù)據(jù)庫建立連接Connection connection=ConnectionMysql.GetConnection();//2.創(chuàng)建并拼裝SQL語句String Sql="insert into Image values(null,?,?,?,?,?,?)";PreparedStatement preparedStatement=connection.prepareStatement(Sql);preparedStatement.setString(1,image.getImageName());preparedStatement.setInt(2,image.getImageSize());preparedStatement.setString(3,image.getImageTime());preparedStatement.setString(4,image.getConteneType());preparedStatement.setString(5,image.getContentPath());preparedStatement.setString(6,image.getMd5());//3.執(zhí)行SQL語句int len=preparedStatement.executeUpdate();if(len==1){System.out.println("插入圖片的操作成功");}else{System.out.println("插入圖片的操作失敗");// throw new UnsupportedOperationException("當(dāng)前數(shù)據(jù)庫執(zhí)行插入操作失敗");throw new JavaOperateMysql("當(dāng)前數(shù)據(jù)庫插入操作失敗"); 當(dāng)我們的程序?qū)懙竭@里的時候,還是會發(fā)生問題,當(dāng)我們上面的任意一個操作拋出異常的時候 就會直接自己跳轉(zhuǎn)到Catch語句或者是程序異常終止 所謂一我們后面的關(guān)閉資源的操作就有可能執(zhí)行失敗,我們根本的目的就是無論程序是否出現(xiàn)異常,我們都要進(jìn)行最終的一個資源關(guān)閉操作 所以最好好把關(guān)閉資源的操作放到finally里面,程序的代碼可能會爆紅,我們就把代碼字段變成全局變量}//4.關(guān)閉連接ConnectionMysql.Close(null,preparedStatement,connection);}public List<Image> SelectAll() throws SQLException {//1.與數(shù)據(jù)庫建立連接Connection connection=ConnectionMysql.GetConnection();//2.拼裝SQL語句String SQL="select * from Image";//3.執(zhí)行SQL語句PreparedStatement preparedStatement= connection.prepareStatement(SQL);ResultSet resultSet= preparedStatement.executeQuery();List<Image> list=new ArrayList<>();//4.遍歷結(jié)果集,返回結(jié)果while(resultSet.next()){Image image=new Image();image.setImageID(resultSet.getInt("ImageID"));image.setContentPath(resultSet.getString("ContentPath"));image.setImageTime(resultSet.getString("ImageTime"));image.setMd5(resultSet.getString("md5"));image.setImageSize(resultSet.getInt("ImageSize"));image.setImageName(resultSet.getString("ImageName"));image.setConteneType(resultSet.getString("ContentType"));System.out.println(image);list.add(image);}//5.關(guān)閉連接ConnectionMysql.Close(resultSet,preparedStatement,connection);return list;}public Image SelectOne(int ImageID) throws SQLException {//1.與數(shù)據(jù)庫建立連接Connection connection=ConnectionMysql.GetConnection();//2.拼裝SQL語句String sql="select * from Image where ImageID=?";//3.執(zhí)行SQL語句PreparedStatement preparedStatement= connection.prepareStatement(sql);preparedStatement.setInt(1,ImageID);ResultSet resultSet= preparedStatement.executeQuery();//4.處理結(jié)果集Image image=new Image();while(resultSet.next()){image.setImageID(resultSet.getInt("ImageID"));image.setContentPath(resultSet.getString("ContentPath"));image.setImageTime(resultSet.getString("ImageTime"));image.setMd5(resultSet.getString("md5"));image.setImageSize(resultSet.getInt("ImageSize"));image.setImageName(resultSet.getString("ImageName"));image.setConteneType(resultSet.getString("ContentType"));}ConnectionMysql.Close(resultSet,preparedStatement,connection);return image;}public void Delete(int ImageID) throws SQLException {//1.與數(shù)據(jù)庫建立連接Connection connection=ConnectionMysql.GetConnection();//2.拼裝SQL語句String SQL ="delete from Image where ImageID=?";//3.執(zhí)行SQL語句PreparedStatement preparedStatement=connection.prepareStatement(SQL);int len= preparedStatement.executeUpdate();if(len==1){System.out.println("刪除成功");}else{System.out.println("刪除失敗");}//4.關(guān)閉資源ConnectionMysql.Close(null,preparedStatement,connection);} }

如何進(jìn)行打JAR包:

1.普通方法:

1)注意:當(dāng)前我們的數(shù)據(jù)庫是在阿里云服務(wù)器上面,也就是在咱們的linux上面,不是在本地的windows系統(tǒng)上面,我們直接通過上述代碼是不可以進(jìn)行直接在本地訪問咱們的數(shù)據(jù)庫,所以我們需要把這些程序部署到我們的云服務(wù)器上面才可以看到效果

2)我們的解決方法就是直接打一個jar包,我們直接把這個jar包直接拷貝到我們的云服務(wù)器上面就可以了

3)我們直接點(diǎn)擊File目錄中的Project Structure會顯示Project Setting,然后我們直接點(diǎn)擊Artifacts,然后在進(jìn)行點(diǎn)擊+,點(diǎn)擊jar,在進(jìn)行點(diǎn)擊mainclass,選擇我們的入口類(表示要從哪一個類開始執(zhí)行)(這個入口類必須有main方法)

4)JAR包:本質(zhì)上來說就是一個zip壓縮包,本質(zhì)上來說就是一大堆的.class文件,我們會把一大堆的.class文件放在一起,打包成一個文件

5)最后我們點(diǎn)擊Build點(diǎn)擊BuildAtifacts就可以進(jìn)行打包操作了,打包之后,就會自動生成jar包

6)先把jar包拖到linux上面,運(yùn)行我們的jar包:java -jar +jar包名字,我們就可以進(jìn)行運(yùn)行jar包了,我們按下回車之后,系統(tǒng)雖然沒有給任何的提示,但是如果說最后咱們的jar包運(yùn)行錯誤,那么一定會拋出一個異常,會打印異常調(diào)用棧的信息

下面是我寫代碼的時候出現(xiàn)的兩個錯誤

while(resultSet!=null){Image image=new Image();image.setImageID(image.getImageID());image.setContentPath(image.getContentPath());image.setImageTime(image.getImageTime());image.setMd5(image.getMd5());image.setConteneType(image.getConteneType());} //1.第一個判定條件是result.next //2.第二個寫的啥也不是,具體的值應(yīng)該從result中獲取

我們可以通過單元測試的方法對程序進(jìn)行驗(yàn)證,所謂的單元測試,就是把一個類或者是一個方法作為一個單元,一旦出現(xiàn)問題,我們就可以盡早地發(fā)現(xiàn)BUG,BUG發(fā)現(xiàn)的越早,我們的解決成本就越低?

總結(jié)

以上是生活随笔為你收集整理的零基础编写图片服务器(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。