SpringMVC从数据库中读取图片显示到JSP页面上

 摸索了一个多星期,终于解决了展示瀑布流照片墙的问题,我一直在思考照片放在哪里,前后想了很多方案。最开始是想把照片放在本地(我的E盘中),而数据库中只存照片的名字,但是这种方案遇到了瓶颈,我不知道img标签的src路径怎么写,不能直接写我本地的路径,在网上看了很多,说是要把图片放到服务器下。但是这样我又遇到了一个问题(问题真是频繁啊),因为我创建的是maven工程,之前把maven工程部署到自己配置的tomcat服务器上的时候各种错误,并且也没解决这个问题,我只好将maven工程部署到了STS自带的tomcat服务器上,那现在要把图片放在服务器的目录下,就需要找到tomcat的webapp目录,自己配置的服务器的话这个目录很好找,但是STS自带的tomcat服务器这个目录我又不知道在哪里,所以这种方案又放弃了。既然我找不到这个目录,网上又说可以把自己的某个文件夹当做服务器下的文件夹,所以把我想修改tomcat的server.xml文件,同样是由于找不到STS自带的tomcat服务器下的这个目录,所以这种方案我研究了很久还是不行。后来我又想着还是把图片转换成二进制流存到数据库里面吧,然后再从数据库中读出来,之前我一直想着把图片信息转换成json字符串传递到前台,传递到前台这个过程我是做到了,但是如何在前台将图片的二进制信息转换成图片显示呢,这个过程我又纠结了很久,我一直在想着在js中如何将图片的二进制流转换成图片显示,但是在网上找了很久之后,大家有的说js不能处理二进制流,这种办法也不适用。

      后来是通过把图片二进制信息写入到HttpServletResponse 的outputStream输出流中来展示的,最开始我只是在SpringMVC的一个controller中来处理这个过程,将这一个controller中同时处理,然后返回jsp页面,发现根本不行啊,下面是我当时错误的代码形式:

  1. <span style="font-family:Comic Sans MS;">     @RequestMapping(value="/toLookImage",method = RequestMethod.GET)  
  2.      public String lookImage(@PathParam("id")int id,HttpServletRequest request,HttpServletResponse response,Model model){  
  3.          HttpSession seesion = request.getSession();  
  4.            
  5.         Photo photo=photoService.getPhotoById(new BigDecimal(id));  
  6.         byte[] data=photo.getPhotoData();  
  7.         response.setContentType("img/jpeg");  
  8.         response.setCharacterEncoding("utf-8");  
  9.         try {  
  10.               
  11.             OutputStream outputStream=response.getOutputStream();  
  12.             InputStream in=new ByteArrayInputStream(data);  
  13.             int len=0;  
  14.             byte[]buf=new byte[1024];  
  15.             while((len=in.read(buf,0,1024))!=-1){  
  16.                 <span style="color:#cc0000;"><strong>outputStream.write(buf, 0, len);</strong></span>  
  17.             }  
  18.             outputStream.close();  
  19.         } catch (IOException e) {  
  20.             // TODO Auto-generated catch block  
  21.             e.printStackTrace();  
  22.         }  
  23.         return "test";  
  24.           
  25.      }</span>  

其中test.jsp便是我要显示图片的页面,原来我犯了很蠢的错误,应该让一个Controller来返回页面,另一个Controller来显示图片。终于这样我实现了从数据库中读取图片然后显示到页面上。下面来展示下我正确的代码流程:


(1)首先将图片上传然后存到数据库中,代码如下:

  1. <span style="font-family:Comic Sans MS;">@Controller  
  2. @Configuration  
  3. @ImportResource("classpath:spring.xml")  
  4. @RequestMapping("/photo")  
  5. public class FileUploadController {  
  6.       
  7.     @Resource  
  8.     private IPhotoService photoService;  
  9.     @RequestMapping(value="/tofile")  
  10.    public String toFileUpLoad(HttpServletRequest request,Model model){  
  11.        return "fileUpLoad";  
  12.    }  
  13.     //@Value("#{settings['picPath.picUrl']}")  
  14.     @Value("${picUrl}")  
  15.     private  String picUrl;  
  16.       
  17.     public void setPicUrl(String picUrl) {  
  18.         this.picUrl = picUrl;  
  19.     }  
  20.     @RequestMapping("/addAction.do")  
  21.     @ResponseBody//将返回结果写到response中  
  22.     public String save(HttpServletRequest request,HttpServletResponse response,Model model,@RequestParam(value="photo",required=false)MultipartFile filedata) throws UnsupportedEncodingException{  
  23.            
  24.         if(filedata!=null&&!filedata.isEmpty()){  
  25.             //获取图片的文件名  
  26.             String fileName=filedata.getOriginalFilename();  
  27.             //获取图片的扩展名  
  28.             String extensionName=fileName.substring(fileName.lastIndexOf(".")+1);  
  29.             //新的图片名=获取时间戳+"."图片扩展名  
  30.             String newFileName=String.valueOf(System.currentTimeMillis())+"."+extensionName;  
  31.             System.out.println(picUrl);  
  32.             //将图片上传到服务器  
  33.             //saveFile(newFileName,filedata);  
  34.             saveFile(request,fileName,filedata);  
  35.             //将图片名称保存至数据库  
  36.             <span style="color:#cc0000;"><strong>photoService.insert(fileName,filedata.getBytes());</strong></span>  
  37.             //图片路径  
  38.             String realPath=request.getSession().getServletContext().getRealPath(picUrl+"\\"+newFileName);  
  39.             System.out.println("cddd:"+realPath);     
  40.         }  
  41.           
  42.         JSONArray jsonArray=new JSONArray();  
  43.         for(int i=3;i<4;i++){  
  44.             Photo p=photoService.getPhotoById(new BigDecimal(i));  
  45.             jsonArray.add(p);  
  46.         }  
  47.         return jsonArray.toString();  
  48.     }  
  49.     private void saveFile(HttpServletRequest request,String newFileName, MultipartFile filedata) {  
  50.         //根据配置文件获取服务器图片存放路径  
  51.         String saveFilePath=picUrl;  
  52.         //构建文件目录  
  53.         File tempFile=new File(saveFilePath);  
  54.         if(!tempFile.exists()){  
  55.             tempFile.mkdirs();  
  56.         }  
  57.         //保存文件到服务器  
  58.             FileOutputStream fos;  
  59.             try {  
  60.                 fos = new FileOutputStream(saveFilePath+"\\"+newFileName);  
  61.                 fos.write(filedata.getBytes());  
  62.                 //fos.flush();  
  63.                 fos.close();  
  64.             } catch (Exception e) {  
  65.                 // TODO Auto-generated catch block  
  66.                 e.printStackTrace();  
  67.             }  
  68.         }  
  69.       
  70.     }</span>  

图片上传的jsp页面代码如下:
  1. <span style="font-family:Comic Sans MS;"><%@ page language="java" contentType="text/html; charset=UTF-8"  
  2. pageEncoding="UTF-8"%>  
  3. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  4. <html>  
  5. <head>  
  6. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  7. <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/jquery-1.8.3.min.js"></script>  
  8. <script type="text/javascript" src="${pageContext.request.contextPath}/static/js/photo.js"></script>  
  9. <title>upLoadFile</title>  
  10. </head>  
  11. <body>  
  12.  <form action="addAction.do" method="post" enctype="multipart/form-data">  
  13.  <table>  
  14.     <tr>  
  15.         <td width="100" align="right">照片:</td>  
  16.         <td><input type="file" name="photo"/></td>   
  17.     </tr>  
  18.  </table>  
  19.  <input type="submit" id="pclick"/>  
  20.  </form>  
  21. </body>  
  22. </html></span>  

(2)将图片从数据库中读取出来,输出到页面上显示

      首先用一个Controller来返回显示图片的页面:

     

  1. <span style="font-family:Comic Sans MS;">//跳转到图片显示的页面  
  2.      @RequestMapping(value="/toImageDisplay")  
  3.      public String toImageDisplay(){  
  4.          return "waterfullPic";  
  5.      }</span>  

我的waterfullPic.jsp页面如下:

  1. <span style="font-family:Comic Sans MS;">   </head>  
  2.      <body>  
  3.           <div id="main">  
  4.         <div class="pin">  
  5.             <div class="box">  
  6.               <img src="/Login_ssm_mav_picbyte/user/toLookImage?id=13">  <!-- 注意这里的访问路径是正确的是,之前因为在web.xml文件中写成了png,所以折腾了很久 -->  
  7.             </div>  
  8.         </div>  
  9.         <div class="pin">  
  10.             <div class="box">  
  11.               <!-- <img src='/Login_ssm_mav_picbyte/static/pic/img2.jpg'> -->  
  12.               <img src="/Login_ssm_mav_picbyte/user/toLookImage?id=14">  
  13.             </div>  
  14.         </div>  
  15.         <div class="pin">  
  16.             <div class="box">  
  17.               <img src="/Login_ssm_mav_picbyte/user/toLookImage?id=15">  
  18.             </div>  
  19.         </div>  
  20.         <div class="pin">  
  21.             <div class="box">  
  22.               <img src="/Login_ssm_mav_picbyte/user/toLookImage?id=16">  
  23.             </div>  
  24.         </div>  
  25.         <div class="pin">  
  26.             <div class="box">  
  27.               <img src="/Login_ssm_mav_picbyte/user/toLookImage?id=17">  
  28.             </div>  
  29.         </div>  
  30.     </div>  
  31. </body></span>  

<img src="/Login_ssm_mav_picbyte/user/toLookImage?id=13"> src即为向/Login_ssm_mav_picbyte/user/toLookImage路径发出请求,而这个请求对应的Controller处理代码如下:
  1. <span style="font-family:Comic Sans MS;">//将图片输出到页面进行显示  
  2.      @RequestMapping(value="/toLookImage",method = RequestMethod.GET)  
  3.      public void lookImage(@PathParam("id")int id,HttpServletRequest request,HttpServletResponse response,Model model){  
  4.          HttpSession seesion = request.getSession();  
  5.         Photo photo=photoService.getPhotoById(new BigDecimal(id));  
  6.         byte[] data=photo.getPhotoData();  
  7.         response.setContentType("img/jpeg");  
  8.         response.setCharacterEncoding("utf-8");  
  9.         try {  
  10.               
  11.             OutputStream outputStream=response.getOutputStream();  
  12.             InputStream in=new ByteArrayInputStream(data);  
  13.               
  14.             int len=0;  
  15.             byte[]buf=new byte[1024];  
  16.             while((len=in.read(buf,0,1024))!=-1){  
  17.                 outputStream.write(buf, 0, len);  
  18.             }  
  19.             outputStream.close();  
  20.         } catch (IOException e) {  
  21.             // TODO Auto-generated catch block  
  22.             e.printStackTrace();  
  23.         }  
  24.           
  25.      }</span>  
我是通过请求中传递过来的id到数据库中取出图片。在这里我遇到了两个注解@PathParam和@RequestParam,我查了下这两个的区别,这里就不再介绍了,不懂的话可以再去网上查查。
这样便可以将图片从数据库中读取出来显示到页面上了。

另外瀑布墙要随着滚动条滚动动态加载图片,我在js中实现了这个功能,那么js中该如何设计这些Img的src呢?
我可能用了比较笨拙的办法,我是先把要显示的图片从数据库中全部读取出来,取出他们的数据,然后json格式的格式传递到前台在前台从json字符串中取出id再设置到请求路径中去。

首先我用一个Controller来从数据库中读取出具,代码如下:

  1. <span style="font-family:Comic Sans MS;">//从数据库中读取信息转换成json格式传递到前台  
  2.      @RequestMapping("/picToJsonReturn.do")  
  3.      @ResponseBody  
  4.      public String picToJsonReturn(HttpServletRequest request,Model model){  
  5.           
  6.          JSONArray jsonArray=new JSONArray();  
  7.         for(int i=13;i<35;i++){  
  8.             Photo p=photoService.getPhotoById(new BigDecimal(i));  
  9.             jsonArray.add(p);  
  10.         }  
  11.         return jsonArray.toString();  
  12.      }</span>  

前台接收的js代码如下:
  1. <span style="font-family:Comic Sans MS;">    function sscroll(){  
  2.      var pic;//原来要把变量定义在这里,之前定义在外面,就会出现undefined的错误  
  3.      $.ajax({  
  4.         async:false,  
  5.         type:'get',//get是获取数据,post是带数据的向服务器发送请求  
  6.         //url:'addAction.do',  
  7.         <strong><span style="color:#cc0000;">url:'picToJsonReturn.do',</span></strong>  
  8.         dataType:'json',  
  9.         success:function(data){  
  10.             pic=eval(data);//转换成js对象  
  11.         },  
  12.         error:function(data){  
  13.             alert("JSON数据获取失败,请联系管理员!");  
  14.         }  
  15.     });</span>  

url:'picToJsonReturn.do',这一行就代表向后台发出请求,data即为后台传递过来的json字符串,这里要主要变量要定义在funcation中不然打印alert(pic)时便会出现Object Object这些,下面是我的动态显示照片墙的js的代码:


  1. <span style="font-family:Comic Sans MS;">window.onload=function(){/*当页面加载的时候调用函数*/  
  2.   setInterval(function(){window.onscroll   = sscroll();},1000);  
  3.   waterfall('main','pin');  
  4.    window.onscroll=sscroll();  
  5. }  
  6. /*之前将函数写在里面时一直实现不了,现在这样写在外面便可以了。*/  
  7.   
  8. function sscroll(){  
  9.     <span style="color:#cc0000;"><strong>var pic;//原来要把变量定义在这里,之前定义在外面,就会出现undefined的错误</strong></span>  
  10.     $.ajax({  
  11.         async:false,  
  12.         type:'get',//get是获取数据,post是带数据的向服务器发送请求  
  13.         //url:'addAction.do',  
  14.         url:'picToJsonReturn.do',  
  15.         dataType:'json',  
  16.         success:function(data){  
  17.             <span style="color:#ff0000;"><strong>pic=eval(data);//转换成js对象</strong></span>  
  18.         },  
  19.         error:function(data){  
  20.             alert("JSON数据获取失败,请联系管理员!");  
  21.         }  
  22.     });  
  23.       
  24.       
  25.     var dataInt={'data':[{'src':'img1.jpg'},{'src':'img2.jpg'},{'src':'img3.jpg'},{'src':'img4.jpg'},{'src':'img5.jpg'},{'src':'img6.jpg'}]};  
  26.     if(checkscrollside()){  
  27.             var oParent=document.getElementById('main');  
  28.             for(var i=0;i<pic.length;i++){  
  29.                 var oPin=document.createElement('div');//添加元素节点  
  30.                 oPin.className='pin';  
  31.                 oParent.appendChild(oPin);  
  32.                 var oBox=document.createElement('div');  
  33.                 oBox.className='box';  
  34.                 oPin.appendChild(oBox);  
  35.                 var oImg=document.createElement('img');  
  36.                 //oImg.src='/Login_ssm_mav_picbyte/static/pic/'+dataInt.data[i].src;  
  37.                 <span style="color:#cc0000;"><strong>oImg.src=src='/Login_ssm_mav_picbyte/user/toLookImage?id='+pic[i].photoId;</strong></span>  
  38.                 //oImg.src='http://localhost:9988/pic/'+pic[i].photoName;  
  39.                 oBox.appendChild(oImg);  
  40.             }  
  41.             waterfall('main','pin');  
  42. }  
  43. }  
  44. function waterfall(parent,pin){  
  45.   
  46.     var oParent=document.getElementById(parent);//父级对象  
  47.     var aPin=getClassObj(oParent,pin);//获取存储pin的数组的pin  
  48.     var iPinW=aPin[0].offsetWidth;//一个块框pin的宽  
  49.     var num=Math.floor(document.documentElement.clientWidth/iPinW);//每行中能容纳的pin的个数[窗口的宽度除以一个块框的宽度]  
  50.     oParent.style.cssText='width:'+iPinW*num+'px;margin:0 auto;';//设置父级居中样式:定宽+自动水平外边距  
  51.   
  52.      var pinHArr=[];//用于存储没列中的所有块框相加的高度  
  53.      for(var i=0;i<aPin.length;i++){  
  54.         var pinH=aPin[i].offsetHeight;  
  55.         if(i<num){  
  56.             pinHArr[i]=pinH;//第一行中的num个块框pin先添加进数组pinHrr  
  57.         }else{  
  58.             var minH=Math.min.apply(null,pinHArr);//数组pinHArr中的最小值  
  59.             var minHIndex=getminHIndex(pinHArr,minH);//获取高度最小的pin的index  
  60.             aPin[i].style.position='absolute';//设置绝对偏移  
  61.             aPin[i].style.top=minH+'px';  
  62.             aPin[i].style.left=aPin[minHIndex].offsetLeft+'px';  
  63.             pinHArr[minHIndex]+=aPin[i].offsetHeight;//更新添加了快框后的列高  
  64.         }  
  65.      }  
  66. }     
  67.   
  68. //获取高度最小的pin 的index  
  69. function getminHIndex(arr,minH){  
  70.     for(var i in arr){  
  71.         if(arr[i]==minH){  
  72.             return i;  
  73.         }  
  74.     }  
  75. }  
  76.   
  77. /*通过父级和子元素的class名称获取该同类子元素的数组*/  
  78. function getClassObj(parent,className){  
  79.     var obj=parent.getElementsByTagName('*');//获取父类元素的所有子元素  
  80.     var pinS=[];//创建一个数组,用于收集子元素  
  81.     for(var i=0;i<obj.length;i++){//遍历子元素,判断类别,压入数组  
  82.         if(obj[i].className==className){  
  83.             pinS.push(obj[i]);  
  84.         }  
  85.     }  
  86.     return pinS;  
  87. }  
  88.   
  89. function checkscrollside(){  
  90.     var oParent=document.getElementById('main');  
  91.     var aPin=getClassObj(oParent,'pin');  
  92.     var lastPinH=aPin[aPin.length-1].offsetTop+Math.floor(aPin[aPin.length-1].offsetHeight/2);  
  93.     //创建【触发添加块框的的函数waterfall()】的高度:最后一个块框的与网页顶部的距离+自身高的一半(未滚到底便开始加载)  
  94.       
  95.     //网页中获取滚动条卷去部分的高度  
  96.     var scrollTop=document.documentElement.scrollTop||document.body.scrollTop;  
  97.     var documentH=document.documentElement.clientHeight;//页面高度  
  98.     return (lastPinH<scrollTop+documentH)?true:false;//到达指定高度后返回true,触发waterfall()函数  
  99. }</span>  

看我funcation  sscroll()中会随着滚动条滚动增加Img标签,该标签的src我写的是:
oImg.src=src='/Login_ssm_mav_picbyte/user/toLookImage?id='+pic[i].photoId;
即从后台传递过来的json字符串中取出id。


整个图片展示的工程也就大致是上面描述的那样,可能我描述的比较乱。

另外要注意很多关于路径的问题,我总是会碰到访问路径的问题。

比如说访问webapp下面的static/pic文件夹下的图片,访问路径应该是:/Login_ssm_mav_picbyte/static/pic/

后面我会再想想之前想的另一种方案,即将图片存在我的E盘中,而数据库中只保存图片的名字。

猜你喜欢

转载自blog.csdn.net/starskyboy/article/details/52252201
今日推荐