2016年6月12日 星期日

Spring MVC中return ModelAndView以及return String


return ModelAndView經查詢是Spring 2.0之前版本所使用方式

如同上一個範例所寫


@RequestMapping("/hello_path")
public ModelAndView hello() {
  String message = "<h1>Hello World!</h1>";
  return new ModelAndView("hello", "message_el", message);
 }


改寫成retrun String則為


@RequestMapping("/hello_path")
public String hello(Model model){
 String message = "<h1>Hello World!</h1>";
 model.addAttribute("message_el", message);
 return "hello";
}

皆為相同作用
String是較新的做法

2016年6月9日 星期四

Spring MVC 初學

剛接觸Spring MVC
寫個簡易教學備忘一下

流程:
1.建立一個Maven專案
我是使用maven-archetype-quickstart
version 1.1
可以直接使用內建Dynamic Web Module的

2.安裝JAR檔



 <dependencies>

  <dependency>

   <groupId>org.springframework</groupId>

   <artifactId>spring-webmvc</artifactId>

   <version>4.2.6.RELEASE</version>

  </dependency>

  <dependency>

   <groupId>junit</groupId>

   <artifactId>junit</artifactId>

   <version>3.8.1</version>

   <scope>test</scope>

  </dependency>

  <dependency>

   <groupId>mysql</groupId>

   <artifactId>mysql-connector-java</artifactId>

   <version>5.1.6</version>

  </dependency>

  <dependency>

   <groupId>org.springframework</groupId>

   <artifactId>spring-jdbc</artifactId>

   <version>4.2.6.RELEASE</version>

  </dependency>

  <dependency>

   <groupId>javax.servlet</groupId>

   <artifactId>javax.servlet-api</artifactId>

   <version>3.1.0</version>

  </dependency>

  <dependency>

   <groupId>jstl</groupId>

   <artifactId>jstl</artifactId>

   <version>1.2</version>

  </dependency>

 </dependencies>





3.轉換為Dynamic Web專案(使用的archetype有內建的就跳過吧)
專案上按右鍵
Properties -> Project Facets -> Covert to faceted form... ->
打勾Dynamic Web Module  ->Apply ->OK

4.轉換為符合maven標準的資料夾格式(使用的archetype以符合就跳過)
在src/main 新增resources資料夾
在src/main 新增webapp資料夾
在src/main/webapp 新增WEB-INF資料夾
專案上按右鍵
Properties -> Deployment Assembly
Add -> Folder 選取src/main/webapp確認
Add -> Java Build Path Entries 選取Maven Dependencies確認


5.新增web.xml
放置於src/main/webapp/WEB-INF/web.xml


<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">

  <display-name>Spring MVC DEMO</display-name>

  <welcome-file-list>

    <welcome-file>index.jsp</welcome-file>

  </welcome-file-list>

 

    <servlet>

        <servlet-name>dispatcher</servlet-name>

        <servlet-class>

            org.springframework.web.servlet.DispatcherServlet

        </servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>dispatcher</servlet-name>

        <url-pattern>*.do</url-pattern>

    </servlet-mapping>

 

</web-app>



6.新增dispatcher-servlet.xml
放置於src/main/webapp/WEB-INF/dispatcher-servlet.xml



<beans xmlns="http://www.springframework.org/schema/beans"

 xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="

        http://www.springframework.org/schema/beans    

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/mvc

        http://www.springframework.org/schema/mvc/spring-mvc.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd">



 <context:component-scan base-package="controller" />



 <bean id="viewResolver"

  class="org.springframework.web.servlet.view.UrlBasedViewResolver">

  <property name="viewClass"

   value="org.springframework.web.servlet.view.JstlView" />

  <property name="prefix" value="/WEB-INF/jsp/" />

  <property name="suffix" value=".jsp" />

 </bean>



</beans>



7.新增一個package命名為controller
在裡面放置一個Hello.java



package controller;



import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.servlet.ModelAndView;





@Controller

public class Hello { 

 

 @RequestMapping("/hello_path")

 public ModelAndView hello() {

  

  String message = "<h1>Hello World!</h1>";

  return new ModelAndView("hello", "message_el", message);

 }



}

8.在WEB-INF內新增一個資料夾命名為jsp
在jsp資料夾內放置一個hello.jsp
src/main/webapp/WEB-INF/jsp/hello.jsp


<%@ page language="java" contentType="text/html; charset=BIG5"
    pageEncoding="BIG5"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Spring MVC Demo</title>
</head>
<body>
${message_el}
</body>
</html>

9.啟動tomcat
網址輸入
http://localhost:8080/ProjectName/hello_path.do
ProjectName看你取什麼名字就打什麼






總結一下Spring MVC的運作流程
從web.xml讀取DispatcherServlet dispatcher取的servlet-name後面加上-servert.xml就是它會去找的檔案名稱
我這邊把servlet-name取名為dispatcher所以它去尋找dispatcher-servlet.xml
之後從dispatcher-servlet.xml讀取JstlView
這邊能夠設定prefix與suffix
對應到的就是設定jsp檔案的路徑以及檔案的副檔名
以及能夠設定該去掃描哪個package
會去scan此package底下的Class檔案中的annotation
而此範例是寫了一個@Controller
告訴Spring這是一個Controller Class
底下的方法就是設置@RequestMapping
@RequestMapping對應的是網址列該打上的path
也可以加入method
@RequestMapping(value = "/hello_path", method = { RequestMethod.GET, RequestMethod.POST })
初學容易搞混web.xml設置的url-pattern與@RequestMapping的路徑有什麼不同
web.xml的url-pattern是設定怎樣的path要去找spring的dispatcher來做轉發
所以也可以在web.xml內設定專門給servlet用的路徑
本範例是使用路徑結尾為.do的交由spring mvc做轉發處理
http://localhost:8080/ProjectName/hello_path.do
看到.do便知道此request先交由spring mvc dispatcher處理
spring mvc會去比對@RequestMapping是否有value是hello_path的
於是轉交該方法來執行
此範例return為ModelAndView物件
return new ModelAndView("hello", "message", message);
ModelAndView(String viewName, String modelName, Object modelObject)
hello代表的是jsp檔名
在dispatcher-servlet.xml中我們已經設定了
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
所以spring mvc會解譯為 /WEB-INF/jsp/hello.jsp
能夠對應到server端內的資料夾路徑
modelName message_el就是帶往jsp檔案時相對應的名稱 能夠用EL $(message_el}來call massege物件
而message物件就是我們在hello方法內所寫的String message

相關檔案放在
https://gist.github.com/ripple0129/45872576a10615819c15ab81a06fdfe4

2015年12月28日 星期一

遊戲腳本撰寫紀錄

由於有網友對於遊戲的腳本製作過程有興趣

這篇也算是紀錄一下我寫手機遊戲腳本的心得

太細節的部份就不說明了

要擁有的知識可能有點雜


國際版ROB經歷了四五年總算要關閉服務了

 Rage of bahamut(rob)是一款卡牌遊戲

起源於日本的web卡牌遊戲(開發廠商為cygames)

移植到android與ios而讓卡牌遊戲成為眾多手機app廠商開發的仿效模式

遊戲本質上其實還是web

而mobage(rob代理商)有自己的登入器接口

也就是遊戲開啟後先做login的動作 輸入帳號密碼後

登入系統會配發cookie並redirrect到遊戲的web server

起先我使用bluestacks安卓模擬器來做登入動作

後來由於效能問題又改用了virtualbox直接安裝android os進去來執行

我們要自動化的第一步自然是透過程式讓app自動啟動

如何使用電腦來控制android模擬器 基本上都是使用adb這個程式來控制

adb devices #查詢電腦有無裝置連接
adb connect 192.168.56.1 #連接上位置於192.168.56.1的裝置
"""最常用的基本上就這兩個
只要連接上後續控制就是靠自動化了"""

google本身有提供一套自動化測試工具叫monkeyrunner 個人使用後感覺效能頗差

且在比對圖片時常常會掛掉

後來改用了androidviewclient這一套純python的自動化工具


#自動化連接上裝置範例

from com.dtmilano.android.adb.adbclient import AdbClient
if len(sys.argv) >= 2:
    serialno = sys.argv[1]

else:
    serialno = '.*'
print 'serialno= '+str(serialno)

device1 = AdbClient(serialno=serialno)
print 'connected'

#如果使用python script.py 192.168.56.1 這個script就會去操作192.168.56.1


連接上我們要做的事情自然就是開啟遊戲的app

事實上透過adb shell其實就能夠簡單達到了


#開啟app
adb shell am start -a android.intent.action.MAIN -n com.mobage.ww.a692.Bahamut_Android/.SplashActivity
#關閉app
adb shell pm clear com.mobage.ww.a692.Bahamut_Android
"""啟動的程式名稱可能要先開eclipse觀察logcat看app的啟動流程來知道啟動時的package name
這是adb shell的使用方法,我們寫進腳本內去開啟的方式也差不多,pm clear的話同時能有清除使用者資料的功能"""

遊戲啟動後我們就開始做登入動作

#這邊我設置了一個開頭名稱為test100登入帳號,擷取封包cookie資訊登入後執行script
import time
from PIL import Image,ImageStat
from lib.sniff import sniff_rob #自己寫的擷取封包extract出cookie的module

user_name = "test"
user_num = 100
password = 12345678
delay = 1 #登入帳號之間的間隔秒數
run_script = "script" #登入後帳號所要執行的script


device1.shell("pm clear com.mobage.ww.a692.Bahamut_Android") #androidviewclient下shell的方法
time.sleep(1);
print 'Login: '+user_name+str(user_num)
print 'Password: '+ str(password)
print user_name+str(user_num)+': Run Rage of Bahamut...'
device1.shell("am start -a android.intent.action.MAIN -n com.mobage.ww.a692.Bahamut_Android/.SplashActivity")
time.sleep(5) #我是直接用等待五秒的方式等程式開啟,嚴謹點自然可以找android看有無check程式是否執行中的方法

#開啟app後要比對圖片來確認有無正常開啟app並且比對成功後開始執行登入
i=1
    while i<=8:
    picstart = Image.open("./pic/picstart.png") #用PIL開啟一個圖片
    time.sleep(1);
    picstart2=device1.takeSnapshot(reconnect=True) #利用androidviewclient takeSnapshot method擷取安卓的當前畫面
    picstart2=picstart2.transform((20,20),Image.EXTENT, (120,160,140,180)) #將當前畫面擷取出想要的部分
    print user_name+str(user_num)+': Loading'
    if device1.sameAs(picstart, picstart2, 1)== 1: #比對成功進行以下動作
        i=10 #比對成功後跳出while,由於i==9有其他動作所以用此方式跳出
        print user_name+str(user_num)+': Start to login'
        device1.touch(120,160, 'DOWN_AND_UP') #androidviewclient 模擬點取螢幕120,160的位置
        time.sleep(0.2);
        device1.touch(120,160, 'DOWN_AND_UP')
        time.sleep(0.5);
        device1.shell("input keyevent 61")#下達鍵盤TAB鍵的意思
        time.sleep(1);
        device1.type(user_name + str(user_num)) #輸入帳號
        time.sleep(1);
        device1.shell("input keyevent 61")#TAB換欄位
        device1.type(str(password)) #輸入密碼
        time.sleep(1);
        device1.shell("input keyevent 66")# 點選登入
        user=user_name+str(user_num)
        if sniff_rob(user,'01'): break #擷取出cookie
            filec = open('./cookie/'+user+'.txt','r')
            cookie = filec.read()
            if cookie == '':
                user_num = user_num -1
                break
                #將此帳號執行run_script,由於我使用windows7來跑所以有些導入程式的參數部分看起來比較複雜,也不是什麼重要的地方
                command_lines = 'python ./lib/'+run_script+'.py --'+user 
                print user+' start popen'
                args = shlex.split(command_lines)
                p = Popen(args)

    else: #比對失敗後等兩秒再比對圖片
        i=i+1
        time.sleep(2)



run_script的部分由於還蠻多種script的

都是定義遊戲中腳色要怎麼動作

包含加好友領獎勵過任務之類的

由於都是url.get url.post之類的東西也沒什麼好說明的

而擷取封包是使用scapy有興趣找相關documentation即可

這個程式其實是登入100-999個帳號

我精簡了一些不然有點太囉嗦


2015年4月28日 星期二

Scrapy 使用心得(1)


目前專案在製作一個可以快速搜索遊戲卡片的app
由於已經有相關的wiki了
所以只需要爬資料下來做好search功能

趁現在記憶猶新趕快把心得寫下提醒未來的自己XD

我所使用的環境為: python 2.7, win7 64, mongodb

目的:爬資料進去mongodb

安裝方式為:
pip install scrapy


安裝好了之後開始一個新的專案
scrapy startproject myapp

於是會建立一個
myapp資料夾


檔案結構為
myapp/
    scrapy.cfg
    myapp/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...
spider資料夾內沒有檔案要自行建立spider的檔案
基本上scrapy提供許多種spider
BaseSpider:
from scrapy.spider import BaseSpider
只會爬你提供的url

CrawlSpider:
from scrapy.contrib.spiders import CrawlSpider
會爬你提供的url並把裡面的links也爬一爬

基本上我只使用過這兩種其他就不說明了

BaseSpider使用範例
我們先在spider資料夾內建立一個叫spider.py(檔名可以任意取喔)



from scrapy.spider import BaseSpider


class myappSpiders(BaseSpider): 

 

     name = 'myspider_name' #這個名字很重要喔對scrapy不熟的可能要浪費好幾分鐘在這

     allowed_domains = ['www.example.com']  #要爬的domain


     #start_urls就是爬蟲開始爬的第一個網頁,在BaseSpider中就只爬提供的這些urls
     start_urls = ['http://www.basespider.com/page1'
               ,'http://www.basespider.com/page2'
        ]

    #爬蟲從url爬完會丟到parse內你就可以從這邊設定你想取出的資料是什麼
def parse(self, response): hxs = HtmlXPathSelector(response) item = myappItem() item['item_field'] = hxs.select('//h1[@id="css_id"]/span/text()').extract() return item #這邊看到item = myappItem()與item['item_field']要先到item.py設定好 #return item會把item丟進去pipeline去處理,資料量不多其實這邊寫個file.write就好了

item.py的設定範例


from scrapy.item import Item, Field


class myappItem(Item):
    item_field = Field()

#class要跟spider.py內的myappItem同名, 每個你要抓的item_field都要來設定一下Field()




接著把terminal小黑窗目標移到scrapy.cfg同個位置
執行
scrapy crawl myspider_name
就可以開始抓囉
不要跟我一樣scrapy crawl 檔名浪費好幾分鐘阿XD

等我下次心血來潮再把後面補完QQ







2015年1月23日 星期五

Install scapy with python 2.7 in windows

參考網址
http://www.secdev.org/projects/scapy/doc/installation.html#windows 
得知需要的packages還蠻多的
不過此處列出的都是python 2.5 2.6的package links.

 2.7的找了一下

1. pywin32
http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/

2. Winpcap
http://www.winpcap.org/install/bin/WinPcap_4_1_1.exe

3. pypcap
https://code.google.com/p/pypcap/issues/detail?id=36 

4. libdnet
http://dirk-loss.de/scapy/dnet-1.12.win32-py2.7.exe

5. pyreadline
https://pypi.python.org/pypi/pyreadline/2.0

6. scapy
http://bb.secdev.org/scapy/downloads

除了scapy要解壓縮跑python setup.py之外
剩的都是installer沒什麼安裝問題
這篇應該能夠幫助不少人省下找package的時間

2014年8月8日 星期五

演算法quine python範例

Quine演算法為程式語言經過編譯之後
執行顯示出來的內容必須與原始碼相同

wiki介紹


原本以為很難
要描述顯示出來的內容必須再新添加內容
這樣顯示的內容又會再增加
好像無解一樣

實作後發現比想像中簡單多了

python範例:

s="quine"
v="s=v=l=n='n p="
l=':"()[]+\\'
n='\n'
p='print(v[:2]+l[1]+s+l[1]+n+v[2:4]+l[1]+v+l[1]+n+v[4:6]+v[8]+l+l[7]+v[8]+n+v[6:9]+l[7]+v[9]+v[8]+n+v[11:13]+v[8]+p+v[8]+n+p)'
print(v[:2]+l[1]+s+l[1]+n+v[2:4]+l[1]+v+l[1]+n+v[4:6]+v[8]+l+l[7]+v[8]+n+v[6:9]+l[7]+v[9]+v[8]+n+v[11:13]+v[8]+p+v[8]+n+p) 

複製code執行,顯示結果將會和code一模一樣

2014年7月26日 星期六

Python for對不同datatype的測試


python的for不同於其他語言
感覺簡潔而且強大了許多
但是往往使用起來對概念的理解上也有點心虛阿XD

所以特別測試一下了解for對不同資料型別的處理方式

字串的處理:


for char in string:
  print char

會計算字串有幾個字元
有幾個字元就迴圈幾次


a = "12345"

for i in a

  print i



結果

1

2

3

4

5






列表的處理(Tuple相同):


for element in list:
  print element

會計算列表有多少個元素
有多少個元素就迴圈幾次

a = ( 'L1' , 'L2' , 'L3' , 'L4' , 'L5' ) for i in a
  print i

結果
L1
L2
L3
L4
L5


字典的處理:


for key in dictionary:
  print key

for key in dictionary
  print dictionary[key]  #印出value

有多少個key就迴圈幾次
排列的順序與key值有關
也就是會由小到大來print出來
如果key是string則會以迭代器的位置來開始印
所以想使用for在dictionary上面
最好key值使用integer較好控制
使用string為key值可能會出現非預期的錯誤



a = { 1:'a', 3:'b', 2:'c', 4:'d', 5:'e' } #注意key順序不同


for i in a


  print i





結果以key值大小排序


1

2

3

4

5



如果想要取出value值
則使用
for i in a
  print a[i]
結果以key值大小取出value值
a
c
b
d
e