1. 程式人生 > >Spring MVC:圖片驗證碼的生成與返回

Spring MVC:圖片驗證碼的生成與返回

效果

圖片驗證碼

程式碼

模型

//分類圖片和儲存圖片數量和路徑
public class ImageGroup {
    private String name;    //圖片組名稱
    private int count;//圖片組數量
    private Set<String> paths=new HashSet<String>();//圖片組圖片路徑
    public ImageGroup(String name,int count,String...paths){
        this.name=name;
        this.count=count;
        this
.paths.addAll(Arrays.asList(paths)); } //省略getter和setter方法 }
//生成的圖片組
public class GenerateImageGroup {
    private ImageGroup keyGroup;//關鍵圖片組
    private List<ImageGroup> unkeyGroups;//其他圖片組
    //省略getter和setter方法
}
public class BufferedImageWrap {
    private boolean key;//是否關鍵圖片
    private
String name; private BufferedImage bufferedImage; //省略getter和setter方法 }

生成圖片驗證碼的具體工具類

//用於生成隨機圖片併合並
public class ImageGenerate {
    private static final int WIDTH=100;//一張圖片的寬度
    private static final int HEADER=30;//標題寬度
    private static final int HEIGHT=100;//一張圖片的高度   

    private static String realPath;
    private
static Map<String,ImageGroup> imageGroups=new HashMap<>(); private static Map<Integer,Map<String,ImageGroup>> countImageGroups=new HashMap<>(); public static void init(){ initImageGroup(); initImageGroupMap(); } public static void initImageGroup(){ ImageGroup group=new ImageGroup("訂書機",2,"dsj/1.jpg","dsj/2.jpg"); ImageGroup group0=new ImageGroup("書本",2,"book/1.jpg","book/2.jpg"); ImageGroup group1=new ImageGroup("蘑菇",2,"mg/1.jpg","mg/2.jpg"); ImageGroup group2=new ImageGroup("雲",2,"cloud/1.jpg","cloud/2.jpg"); ImageGroup group3=new ImageGroup("吸鐵石",2,"xts/1.jpg","xts/2.jpg"); ImageGroup group4=new ImageGroup("包包",4,"bb/1.jpg","bb/2.jpg","bb/3.jpg","bb/4.jpg"); ImageGroup group5=new ImageGroup("柚子",4,"yz/1.jpg","yz/2.jpg","yz/3.jpg","yz/4.jpg"); ImageGroup group6=new ImageGroup("糖葫蘆",4,"thl/1.jpg","thl/2.jpg","thl/3.jpg","thl/4.jpg"); ImageGroup group7=new ImageGroup("老虎",4,"lh/1.jpg","lh/2.jpg","lh/3.jpg","lh/4.jpg"); ImageGroup group8=new ImageGroup("土豆",6,"td/1.jpg","td/2.jpg","td/3.jpg","td/4.jpg","td/5.jpg","td/6.jpg"); ImageGroup group9=new ImageGroup("仙人球",6,"xrq/1.jpg","xrq/2.jpg","xrq/3.jpg","xrq/4.jpg","xrq/5.jpg","xrq/6.jpg"); ImageGroup group10=new ImageGroup("兔子",6,"tz/1.jpg","tz/2.jpg","tz/3.jpg","tz/4.jpg","tz/5.jpg","tz/6.jpg"); initImageGroupMap(group,group0,group1,group2,group3,group4,group5,group6,group7,group8,group9,group10); } public static void initImageGroupMap(ImageGroup...groups){ for(ImageGroup group:groups){ imageGroups.put(group.getName(), group); if (!countImageGroups.containsKey(group.getCount())) { countImageGroups.put(group.getCount(), new HashMap<String,ImageGroup>()); } countImageGroups.get(group.getCount()).put(group.getName(), group); } } public static void Genreate(HttpServletResponse response,HttpSession session){ init(); realPath=session.getServletContext().getRealPath("/assets/"); GenerateImageGroup groups=getRandomImageGroup(); List<BufferedImageWrap> images= getBufferedImageGroups(groups); mergeAndReturn(images,response,session); } //合併圖片並返回至頁面 public static void mergeAndReturn(List<BufferedImageWrap> images, HttpServletResponse response,HttpSession session){ Collections.shuffle(images);//打亂原有順序 BufferedImage targetImage=new BufferedImage( 4*WIDTH,HEADER+2*HEIGHT,BufferedImage.TYPE_INT_RGB); int x=0; int y=0; int order=0; List<Integer> keyOrders=new ArrayList<>();//存放關鍵圖片所在位置(0-7) BufferedImage bufferedImage=null; boolean firstKey=true; for(BufferedImageWrap image:images){ bufferedImage=image.getBufferedImage(); int x1=0,y1=0; if(bufferedImage.getWidth()>WIDTH){ x1=RandomIntGenerate.getRandomInt(bufferedImage.getWidth()-WIDTH); } if(bufferedImage.getHeight()>HEIGHT){ y1=RandomIntGenerate.getRandomInt(bufferedImage.getHeight()-HEIGHT); } int[] rgb=bufferedImage.getRGB(x1,y1,WIDTH, HEIGHT,null, 0, WIDTH); if(image.isKey()){ if(firstKey){ Graphics2D g=(Graphics2D)targetImage.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, 4*WIDTH, HEADER); g.setFont(new Font("宋體",Font.PLAIN,14)); g.setColor(Color.BLACK); g.drawString("請在圖下選中所有的 ", 0, HEADER/2); g.setFont(new Font("宋體",Font.BOLD,16)); g.setColor(Color.RED); g.drawString(image.getName(), 150, HEADER/2); firstKey=false; } keyOrders.add(order); } x=(order%4)*WIDTH; y=order<4?HEADER:HEADER+HEIGHT; //System.out.println(x+"\n"+y); targetImage.setRGB(x, y, WIDTH, HEIGHT, rgb, 0, WIDTH); ++order; } session.setAttribute("verifyCode", keyOrders);//將關鍵圖片所在序號存入session try { ImageIO.write(targetImage, "jpg", response.getOutputStream());//往頁面寫回合併的圖片 } catch (IOException e) { e.printStackTrace(); } } public static List<BufferedImageWrap> getBufferedImageGroups(GenerateImageGroup generatedGroups){ List<BufferedImageWrap> imageWraps=new ArrayList<>(); for(String shortPath:generatedGroups.getKeyGroup().getPaths()){ imageWraps.add(new BufferedImageWrap(true,generatedGroups.getKeyGroup().getName(),realPath+shortPath)); } for(ImageGroup group:generatedGroups.getUnkeyGroups()){ for(String shortPath:group.getPaths()){ imageWraps.add(new BufferedImageWrap(false,"",realPath+shortPath)); } } return imageWraps; } public static GenerateImageGroup getRandomImageGroup(){ int randInt; String randName; int leftCount; ImageGroup keyImageGroup; List<ImageGroup> unKeyImageGroups=new ArrayList<>(); //獲取關鍵圖片組 randInt=RandomIntGenerate.getRandomInt(imageGroups.size()); randName=new ArrayList<String>(imageGroups.keySet()).get(randInt); keyImageGroup=imageGroups.get(randName); //移除已選關鍵圖片組 Map<Integer,Map<String,ImageGroup>> tmpMap=new HashMap(countImageGroups); tmpMap.get(keyImageGroup.getCount()).remove(keyImageGroup.getName()); leftCount=8-keyImageGroup.getCount();//最終是用8張小圖片合成一張 List<ImageGroup> groups=null; //非關鍵圖片為6張時 if(leftCount==6){ //為偶數時,得到4+2非關鍵圖片組 if(RandomIntGenerate.getRandomInt()%2==0){ groups=new ArrayList<ImageGroup>(tmpMap.get(4).values()); randInt=RandomIntGenerate.getRandomInt(groups.size()); unKeyImageGroups.add(groups.get(randInt)); groups=new ArrayList<ImageGroup>(tmpMap.get(2).values()); randInt=RandomIntGenerate.getRandomInt(groups.size()); unKeyImageGroups.add(groups.get(randInt)); } //奇數時,得到3*2張圖片組 else{ groups=new ArrayList<ImageGroup>(tmpMap.get(2).values()); for(int i=0;i<3;i++){ randInt=RandomIntGenerate.getRandomInt(groups.size()); unKeyImageGroups.add(groups.get(randInt)); groups.remove(randInt); } } } else if(leftCount==4){ //得到1*4張圖片組 if(RandomIntGenerate.getRandomInt()%2==0){ groups=new ArrayList<ImageGroup>(tmpMap.get(4).values()); randInt=RandomIntGenerate.getRandomInt(groups.size()); unKeyImageGroups.add(groups.get(randInt)); } //得到2*2張圖片組 else{ groups=new ArrayList<ImageGroup>(tmpMap.get(2).values()); for(int i=0;i<2;i++){ randInt=RandomIntGenerate.getRandomInt(groups.size()); unKeyImageGroups.add(groups.get(randInt)); groups.remove(randInt); } } } else if(leftCount==2){ groups=new ArrayList<ImageGroup>(tmpMap.get(2).values()); randInt=RandomIntGenerate.getRandomInt(groups.size()); unKeyImageGroups.add(groups.get(randInt)); } return new GenerateImageGroup(keyImageGroup,unKeyImageGroups); } }
//用於生成隨機數
public class RandomIntGenerate {
    public static Random random=new Random();

    public static int getRandomInt(){
        return random.nextInt();
    }
    public static int getRandomInt(int max){
        return random.nextInt(max);
    }
}

Controller

@Controller
public class VerifyCodeController {
    @RequestMapping("/getVerifyCode")
    public void getVerifyCode(HttpServletResponse response,HttpSession session){
        ImageGenerate.Genreate(response, session);
    }
    @RequestMapping("/verify")
    @ResponseBody
    public String verify(String verifyCode,HttpSession session){
        String [] coordinates=verifyCode.split(";");
        List<Integer> orders=(List<Integer>)session.getAttribute("verifyCode");
        if(coordinates.length!=orders.size()){
            return "unpass";
        }

        int order=0;
        for(String coordinate:coordinates){
            String[] offsets=coordinate.split(",");
            order=getSelectedOrder(Integer.parseInt(offsets[0]),Integer.parseInt(offsets[1]));
            //System.out.println(order);
            if(!orders.contains(order)){
                return "unpass";
            }
        }
        //System.out.println(verifyCode);
        return "pass";
    }

    //根據座標確定使用者選擇了哪幾張圖片
    public int getSelectedOrder(int x,int y){
        int order;
        if(x>300){
            order=3;
        }
        else if(x>200){
            order=2;
        }
        else if(x>100){
            order=1;
        }
        else{
            order=0;
        }

        if(y>100){
            order+=4;
        }
        return order;
    }
}

頁面程式碼

<!--/WEB-INF/pages/index.jsp-->
<html>
<head>
<meta charset="utf-8">
<title>圖片驗證碼實現</title>
<link rel="stylesheet" href="css/index.css"/>
<script src="js/jquery-3.2.1.min.js"></script>
</head>

<body>
<div class="img-wrapper"><img src="getVerifyCode.html"/></div>
<div class="btns-div"> 
    <a href="javascript:void(0);" class="refresh-btn">換一張</a>
    <a href="javascript:void(0);" class="submit-btn">驗證</a>
</div>

<script src="js/index.js"></script>
</body>
</html>
//js/index.js
$(function(){
    var maxWidth=400;
    var maxHeight=200;
    var offset=30;
    var verifyCode="";
    $(".img-wrapper").click(function(e){
        var offsetx=e.offsetX;
        var offsety=e.offsetY;
        if(offsety<30){
            return ;
        }
        var leftVal=offsetx-12;
        var topVal=offsety-12;

        leftVal=leftVal<0?0:leftVal;
        leftVal=leftVal>maxWidth-24?maxWidth-24:leftVal;
        topVal=topVal<offset?offset:topVal;
        topVal=topVal>maxHeight+offset-24?maxHeight+offset-24:topVal;

        var pickDiv=$("<div class='pick-div'><img src='assets/pickon.png'/></div>");
        pickDiv.css("position","absolute");
        pickDiv.css("left",leftVal+"px");
        pickDiv.css("top",topVal+"px");

        verifyCode+=leftVal+","+(topVal-offset)+";";
        //console.log(verifyCode);
        $(this).append(pickDiv);
    });
    $(".img-wrapper").on("click",".pick-div",function(e){
        //console.log(verifyCode);
        var target=$(this)[0].offsetLeft+","+$(this)[0].offsetTop+";";
        verifyCode=verifyCode.replace(target,"");

        $(this).remove();
        e.stopPropagation();
    });
    $(".refresh-btn").click(function(){
        verifyCode="";
        $(".pick-div").remove();
        $(".img-wrapper img").attr("src","getVerifyCode.html?date="+new Date().getTime());
    });
    $(".submit-btn").click(function(){
        verifyCode=verifyCode.substring(0,verifyCode.length-1);
//      console.log(verifyCode);
        $.ajax({
            url:"verify.html",
            data:{"verifyCode":verifyCode},
            type:"POST",
            //dataType:"json",
            success:function(data){
                alert(data);
                $(".refresh-btn").click();
            }
        });
    });
});
<!--css/index.css-->
.img-wrapper{position:relative;}
.img-wrapper img{
    width:400px;
    height:230px;
}
.pick-div{position:absolute;}
.pick-div img{
    width:24px;
    height:24px;
}
.btns-div{
    width:400px;
    text-align:center;
}
.btns-div a{
    display:inline-block;
    line-height:30px;
    width:60px;
    color:#FFF;
    font-size:16px;
    text-align:center;
    text-decoration:none;
    border-radius:1px;
    background-color:#0AC516;
}
.btns-div a:hover{background-color:#0AAA16;}

相關配置

<!--springmvc-servlet.xml-->
<mvc:annotation-driven/>
   <context:component-scan base-package="com.imageverify.controller"/>

    <!-- 配置根檢視 -->
   <mvc:view-controller path="/" view-name="index"/>

   <!-- 靜態資源配置 -->
   <mvc:resources location="/assets/" mapping="/assets/**"/>
   <mvc:resources location="/js/" mapping="/js/**"/>
   <mvc:resources location="/css/" mapping="/css/**"/>

   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
      <property name="prefix" value="/WEB-INF/pages/" />
      <property name="suffix" value=".jsp" />
   </bean>