Java實現12306登錄和查票

前言:

  之前一直打算寫一個模擬12306的工具,一直拖到現在,實在忍不了了,最近艱難的一步一步開始。由於想重新學習一下Java相關的知識,所以使用Java來進行開發,目前總算是有了一點進展,已經實現了登錄和查票功能,先記錄一下。下單以及其他搶票設置還在開發中。。。

界面:

  本文主要是關注功能的實現,另外就是javaswing的排版也不是很擅長,所以界面比較醜陋,將就看一下就行,目前主要是主界面、登錄界面以及日期選擇界面,先看一下效果:
查票結果
登錄界面 日期選擇控件
  這裏說明一下,日期選擇控件是從網上找的一片文章拿過來用的,希望不要見怪。文章地址是:DateChooser日期選擇器sw

車站信息:

  由於車站信息可能會有變化,包括新增車站或者車站改名之類的,所以要保證車站名稱及對應的車站編號是最新的。
  static String getStationUrl = “https://kyfw.12306.cn/otn/resources/js/framework/station_name.js”;
  getStationUrl:爲Get請求,沒有參數。用於獲取全國車站名稱信息,後續的查票操作中需要將中文車站名稱轉換爲對應的車站編號。。

登錄模塊:

  登錄模塊主要是要解決驗證碼部分,其他都好說。目前已經實現完整的驗證碼選擇、提交以及驗證等功能。突然好像忘了加上驗證碼刷新功能了(後續補上)。當前每請求一次會保存一張驗證碼圖片在src同級的yzm目錄下(目錄需要自己創建),後續可以考慮用這些已有的驗證碼做自動識別,這是後話了。下面按請求順序說一下登錄過程中分別請求的幾個URL:
  static String initUrl = “https://kyfw.12306.cn/otn/login/init”;
  string String getJsUrl = "https://kyfw.12306.cn/otn/HttpZF/GetJS
  static String getRailUrl = “https://kyfw.12306.cn/otn/HttpZF/logdevice”+
           “?algID=XWptt1kXbs”+
           “&hashCode=K7H-SogpeC4-tIYLqCXJabQWEnBXNROVnaPuQXU8Vec”+
           “&FMQw=0”+
           “&q4f3=zh-CN”+
           “&VPIf=1”+
           “&custID=133”+
           “&VEek=unknown”+
           “&dzuS=0”+
           “&yD16=0”+
           “&EOQP=89f60554e6cb588cf7dcc391a91488a1”+
           “&lEnu=176525634”+
           “&jp76=52d67b2a5aa5e031084733d5006cc664”+
           “&hAqN=Win32”+
           “&platform=WEB”+
           “&ks0Q=d22ca0b81584fbea62237b14bd04c866”+
           “&TeRS=1010x1680”+
           “&tOHY=24xx1050x1680”+
           “&Fvje=i1l1o1s1”+
           “&q5aJ=-8”+
           “&wNLf=99115dfb07133750ba677d055874de87”+
“&0aew=Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/76.0.3809.100%20Safari/537.36”+
           “&E3gR=c0e12f6dc8fe327988a902df0d354cec”+
           “&timestamp=”+String.valueOf(System.currentTimeMillis());
  static String getYzmUrl = “https://kyfw.12306.cn/passport/captcha/captcha-image64?”;
  static String checkYzmUrl = “https://kyfw.12306.cn/passport/captcha/captcha-check?”;
  static String loginUrl = “https://kyfw.12306.cn/passport/web/login”;

  initUrl:爲Get請求,沒有參數。用於獲取後面請求中的一些cookie信息。
  getJsUrl:爲Get請求,沒有參數。用於請求獲取一個js文件。
  getRailUrl:爲Get請求,參數前面都列出來了。用於請求RAIL_DEVICEID和RAIL_EXPIRATION兩個參數,需要將這兩個參數獲取到,然後添加到cookie中,不然在登錄的時候會重定向到https://www.12306.cn/mormhweb/logFiles/error.html,該頁面顯示“網絡可能存在問題,請您重試一下!”。重點關注請求中的algIDhashCode兩個參數,algID可以從getJsUrl這個請求中返回的js文件中拿到,大概位置在:ab.getJSON("https://kyfw.12306.cn/otn/HttpZF/logdevice" + ("?algID\x3dXWptt1kXbs\x26hashCode\x3d" + e + a), null,hashCode這個參數應該也是衝上述js代碼處獲取到的,但是博主對js文件看不太懂,所以直接用fiddler工具抓了個getRailUrl請求的包,直接從裏面拿出來的hashCode參數。但是這兩個參數應該過一段時間會失效,失效的表現就是在登錄的時候會提示重定向到https://www.12306.cn/mormhweb/logFiles/error.html這個頁面,此時需要重新獲取js文件,重新從js文件裏面獲取這兩個參數,或者通過fiddler工具抓包進行獲取,重新設置到cookie裏面。
  getYzmUrl:爲Get請求,需要攜帶{“login_site”:“E”, “module”:“login”, “rand”:“sjrand”, “callback”:“xxx”, "":“xxx”}這五個參數,另外還有個隨機數。用於獲取驗證碼,返回的是一張圖片,圖片頂部爲點擊驗證碼提示語,下部爲8塊區域,分別顯示8張驗證碼。請求URL示例:https://kyfw.12306.cn/passport/captcha/captcha-image64?login_site=E&module=login&rand=sjrand&1565256427784&callback=jQuery19105951551454704869_1565256422938&=1565256422940
  checkYzmUrl:爲Get請求,需要攜帶{“callback”:“xxx”, “answer”:“xxx”, “rand”:“sjrand”, “login_site”:“E”, “_”:“xxx”}這五個參數,用於校驗驗證碼。其中answer參數爲驗證碼圖片座標,如:194,54,48,48。返回的字符串中result_code爲4代表驗證成功。(目前返回的是jQuery開頭的一串字符串,其中()中間的部分爲json格式,後面12306可能會有變動)
  loginUrl:爲Post請求,需要攜帶{“username”:“xxx”, “password”:“xxx”, “appid”:“otn”, “answer”:“xxx”}這四個參數。answer參數與校驗驗證碼中的answer參數一樣。返回的json中對象中result_code爲0代表登錄成功。(目前返回的爲json格式的數據,後面12306可能會有變動)
  關於驗證碼座標的說明:

  • 整張圖片的大小是:293*190 單位:像素
  • 打字機這一排提示語所在行的寬度爲29
  • 第一排第一張小圖片的範圍是(5,41)~(72,108) 長:67,寬:67 間距都是5px
  • 第二排第一張小圖片的範圍是(5,41+5+67)~(72,41+5+67+67) 長:67,寬:67 間距都是5px
  • 第一排第二張小圖片的範圍是(5+67+5,41)~(5+67+5+67,108) 長:67,寬:67 間距都是5px

查票模塊:

  查票模塊目前不添加cookie中的JSESSIONID、RAIL_DEVICEID、RAIL_EXPIRATION也可以查詢成功,但是後續下單包括支付等操作就需要攜帶上述cookie參數。
  static queryTicketsUrl = “https://kyfw.12306.cn/otn/leftTicket/query?”;
  queryTicketsUrl 爲Get請求,需要攜帶{“leftTicketDTO.train_date”:“xxx”, “leftTicketDTO.from_station”:“xxx”, “leftTicketDTO.to_station”:“xxxx”, “purpose_codes”:“xxx”}這四個參數,分別是出發日期、起始站、終到站和類型。

結尾:

  目前只是簡單的實現了登錄和查票功能。包括根據車次類型過濾等小功能都已實現。後續持續更新下單等其他功能模塊,包括界面優化等功能。

代碼:

  完整代碼:Java實現12306登錄和查詢功能,在之前代碼之前需要在工程的src同級目錄下創建yzm文件夾,用來保存驗證碼圖片,另外sign.jpg文件爲30*30,可以隨便替換,保證大小一致就行。代碼中用到的第三方jar包主要有:
beangle-bundles-my97-4.8
commons-codec-1.12
commons-httpclient-3.1
commons-logging-1.2
fastjson-1.2.58
httpclient-4.5.5
httpcore-4.4.7
jcalendarbutton-1.4.5
ps:

package my12307;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel;

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class My12307 extends JFrame {

	private static final long serialVersionUID = 1L;
	private JTextField cfdField;
	private JTextField mddField;
	private DateChooser dc;
	private ButtonGroup radioGroup;
	private JRadioButton adultRadioButton;
	private JRadioButton studentRadioButton;
	private JTable table;
	private JScrollPane scrollPane;
	private String[] headers = {"車次","出發站","到達站","出發時間","到達時間",
			             "歷時","商務/特等座","一等座","二等座","高級軟臥",
			             "軟臥","動臥","硬臥","軟座","硬座",
			             "無座","其他","備註"};
	private JCheckBox ck01,ck02,ck03,ck04,ck05,ck06;
	private Set<String> ccName;
	private Vector<String> tableHeaders;
	private HashMap<String, String> cityMap;
	private Vector<Vector<String>> gDatas;
	
	public My12307() throws ClientProtocolException, IOException {
		initEntity();
		initFrame();
		Utils.initLogin();
		Utils.initRail();
	}
	
	//獲取車站信息
	private void getStationInfo() {
		HttpGet httpGet = new HttpGet(Utils.getStationUrl);
		try {
			CloseableHttpResponse cHttpResp = Utils.getHttpClient().execute(httpGet);
			HttpEntity entity = cHttpResp.getEntity();
			String result = EntityUtils.toString(entity,"utf-8");
			Utils.putStation2Map(result, cityMap);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void initEntity(){
		ccName = new HashSet<String>();
		cityMap = new HashMap<String, String>();
		gDatas = new Vector<Vector<String>>();
		tableHeaders = new Vector<String>();
		for (int i = 0; i < headers.length; i++) {
			tableHeaders.add(i, headers[i]);
		}
	}
	
	private void initFrame() {
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		int width = 1000;
		int height = 660;
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();//獲得屏幕尺寸
		setBounds((d.width - width)/2, (d.height - height)/2, width, height);
		getContentPane().setLayout(new BorderLayout());
		this.setTitle("12307票票");
		this.setResizable(false);
		this.setIconImage(new ImageIcon("src/icon.jpg").getImage());

		JMenuBar menubar = new JMenuBar();
		JMenu menuDL = new JMenu("登錄");
		//JMenu menuTC = new JMenu("退出");
		JMenu menuQueryM = new JMenu("查詢聯繫人");
		menubar.add(menuDL);
		//menubar.add(menuTC);
		menubar.add(menuQueryM);
		this.setJMenuBar(menubar);
		addLoginListener(My12307.this, menuDL);
		//addLogoutListener(menuTC);
		addQueryMListener(menuQueryM);

		JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 5));
		topPanel.setPreferredSize(new Dimension(1000,70));
		JPanel centerPanel = new JPanel();
		centerPanel.setPreferredSize(new Dimension(1000,380));
		JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 1, 5));
		bottomPanel.setPreferredSize(new Dimension(1000,210));

		//出發地,目的地
		JLabel label1 = new JLabel("出發地:");
		JLabel label2 = new JLabel("目的地:");
		cfdField = new JTextField();
		cfdField.setPreferredSize(new Dimension(cfdField.getWidth(),25));
		cfdField.setColumns(10);
		mddField = new JTextField();
		mddField.setPreferredSize(new Dimension(mddField.getWidth(),25));
		mddField.setColumns(10);

		//成人,學生
		radioGroup = new ButtonGroup();
		adultRadioButton = new JRadioButton("成人");
		studentRadioButton = new JRadioButton("學生");
		radioGroup.add(adultRadioButton);
		radioGroup.add(studentRadioButton);
		adultRadioButton.setSelected(true);

		//出發日期
		JLabel label3 = new JLabel("出發日期:");
		dc = new DateChooser("yyyy-MM-dd");

		//查詢
		JButton queryBbutton = new JButton("查詢");
		addButtonListener(queryBbutton);

		//車次類型
		JLabel label4 = new JLabel("車次類型:");
		JPanel panel1 = new JPanel();
		ck01 = new JCheckBox("GC-高鐵/城際");
		ck02 = new JCheckBox("D-動車");
		ck03 = new JCheckBox("Z-直達");
		ck04 = new JCheckBox("T-特快");
		ck05 = new JCheckBox("K-快速");
		ck06 = new JCheckBox("其他");
		ck01.setName("GC");
		ck02.setName("D");
		ck03.setName("Z");
		ck04.setName("T");
		ck05.setName("K");
		addCheckboxListener(ck01);
		addCheckboxListener(ck02);
		addCheckboxListener(ck03);
		addCheckboxListener(ck04);
		addCheckboxListener(ck05);
		addCheckboxListener(ck06);
		panel1.add(ck01);
		panel1.add(ck02);
		panel1.add(ck03);
		panel1.add(ck04);
		panel1.add(ck05);
		panel1.add(ck06);

		JPanel panel2 = new JPanel();
		panel2.add(label4);
		panel2.add(panel1);

		topPanel.add(label1);
		topPanel.add(cfdField);
		topPanel.add(label2);
		topPanel.add(mddField);
		topPanel.add(adultRadioButton);
		topPanel.add(studentRadioButton);
		topPanel.add(label3);
		topPanel.add(dc);
		topPanel.add(queryBbutton);
		topPanel.add(panel2);

		//查票查詢table
		String[][] content = new String[0][18];
		TableModel model = new DefaultTableModel(content, tableHeaders.toArray());
		table = new JTable();
		DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();
		tcr.setHorizontalAlignment(SwingConstants.CENTER);
		table.setDefaultRenderer(Object.class, tcr);
		table.setRowHeight(30);  //設置行高
		JTableHeader tableHeader = table.getTableHeader();
		tableHeader.setResizingAllowed(false);
		tableHeader.setReorderingAllowed(false);
		tableHeader.setFont(new Font("宋體", 0, 12));
		tableHeader.setForeground(new Color(255,255,255));//設置字體顏色
		tableHeader.setBackground(new Color(33,132,199)); //設置背景顏色
		tableHeader.setPreferredSize(new Dimension(tableHeader.getHeight(),40));
		table.setModel(model);
		Utils.setTableColumnWidth(tableHeaders, table);
			scrollPane = new JScrollPane(table) {
			private static final long serialVersionUID = 1L;
			public Dimension getPreferredSize() {
				return new Dimension(990, 312);
			}
		};
		centerPanel.add(scrollPane);

		//搶票條件設置區
		JPanel passengerPanel = new JPanel();
		JPanel seatTypePanel = new JPanel();
		passengerPanel.setBorder(BorderFactory.createTitledBorder("聯繫人"));
		seatTypePanel.setBorder(BorderFactory.createTitledBorder("席別"));
		passengerPanel.setPreferredSize(new Dimension(100,200));
		seatTypePanel.setPreferredSize(new Dimension(100,200));
		bottomPanel.add(passengerPanel);
		bottomPanel.add(seatTypePanel);

		getContentPane().add(topPanel, BorderLayout.NORTH);
		getContentPane().add(centerPanel, BorderLayout.CENTER);
		getContentPane().add(bottomPanel, BorderLayout.SOUTH);

		//獲取車站信息
		getStationInfo();
	}
	
	private void addLoginListener(JFrame frame, JMenu menu) {
		menu.addMouseListener(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent e) {
			}
			@Override
			public void mousePressed(MouseEvent e) {
			}
			@Override
			public void mouseExited(MouseEvent e) {
			}
			@Override
			public void mouseEntered(MouseEvent e) {
			}
			@Override
			public void mouseClicked(MouseEvent e) {
				System.out.println("點擊登錄");
				LoginDialog loginDialog;
				try {
					loginDialog = new LoginDialog(My12307.this);
					loginDialog.setVisible(true);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
	}
	
	private void addTableRowListener(JTable table) {
		table.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				table.setSelectionBackground(new Color(135,206,250));
				int row = table.getSelectedRow();
				int col = table.getSelectedColumn();
				System.out.println("點擊第"+row+"行"+",第"+col+"列");
			}
		});
	}
	
	private void addCheckboxListener(JCheckBox checkbox) {
		checkbox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				String chName = checkbox.getName();
				if("GC".equals(chName)) {
					if(checkbox.isSelected()) {
						ccName.add("G");
						ccName.add("C");
					}else {
						ccName.remove("G");
						ccName.remove("C");
					}
				}else {
					if(checkbox.isSelected()) {
						ccName.add(chName);
					}else {
						ccName.remove(chName);
					}
				}
				
				//過濾數據
				if(!gDatas.isEmpty()) {
					filterDataByCheckBox();
					addTableRowListener(table);
				}
			}
		});
	}
	
	private void addButtonListener(JButton button) {
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				//清空table
				((DefaultTableModel)table.getModel()).getDataVector().clear();
				table.updateUI();
				//String trainDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString();
				String trainDate = dc.showDate.getText();
				String fromStationName = cfdField.getText();
				String toStationName = mddField.getText();
				String fromStation = cityMap.get(fromStationName);
				String toStation = cityMap.get(toStationName);
				if ("".equals(fromStationName) || fromStation == null) {
					System.out.println("出發車站名有誤,請重新輸入。");
					return;
				}
				if ("".equals(toStationName) || toStation == null) {
					System.out.println("目的車站名有誤,請重新輸入。");
					return;
				}
				String type = "";
				if(radioGroup.getSelection() == adultRadioButton.getModel()) {
					type = "ADULT";
				}else {
					type = "0X00";
				}
				
				String queryTicketsUrl = Utils.queryTicketsUrl+"leftTicketDTO.train_date=" + trainDate
						   + "&leftTicketDTO.from_station=" + fromStation + "&leftTicketDTO.to_station="
						   + toStation + "&purpose_codes=" + type;
				try {
					System.out.println(queryTicketsUrl);
					sendQueryTicketRequest(queryTicketsUrl);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
	}
	
	private void colloctionData(Vector<String> row, String[] resultData) {
		row.add(tableHeaders.indexOf("車次"), resultData[3]);
		row.add(tableHeaders.indexOf("出發站"), Utils.getKeyFromMap(cityMap,resultData[6]));
		row.add(tableHeaders.indexOf("到達站"), Utils.getKeyFromMap(cityMap,resultData[7]));
		row.add(tableHeaders.indexOf("出發時間"), resultData[8]);
		row.add(tableHeaders.indexOf("到達時間"), resultData[9]);
		row.add(tableHeaders.indexOf("歷時"), resultData[10]);
		if(resultData[32] != "") {
			row.add(tableHeaders.indexOf("商務/特等座"), ("".equals(resultData[32]))?"--":resultData[32]);
		}else {
			row.add(tableHeaders.indexOf("商務/特等座"), ("".equals(resultData[25]))?"--":resultData[25]);
		}
		row.add(tableHeaders.indexOf("一等座"), ("".equals(resultData[31]))?"--":resultData[31]);
		row.add(tableHeaders.indexOf("二等座"), ("".equals(resultData[30]))?"--":resultData[30]);
		row.add(tableHeaders.indexOf("高級軟臥"), ("".equals(resultData[21]))?"--":resultData[21]);
		row.add(tableHeaders.indexOf("軟臥"), ("".equals(resultData[23]))?"--":resultData[23]);
		row.add(tableHeaders.indexOf("動臥"), ("".equals(resultData[27]))?"--":resultData[27]);
		row.add(tableHeaders.indexOf("硬臥"), ("".equals(resultData[28]))?"--":resultData[28]);
		row.add(tableHeaders.indexOf("軟座"), ("".equals(resultData[24]))?"--":resultData[24]);
		row.add(tableHeaders.indexOf("硬座"), ("".equals(resultData[29]))?"--":resultData[29]);
		row.add(tableHeaders.indexOf("無座"), ("".equals(resultData[26]))?"--":resultData[26]);
		row.add(tableHeaders.indexOf("其他"), ("".equals(resultData[22]))?"--":resultData[22]);
		//row.add(tableHeaders.indexOf("備註"), resultData[1]);
		gDatas.add(row);
	}
	
	@SuppressWarnings("unchecked")
	private void fillData2Table() {
		if (!gDatas.isEmpty()) {
			Vector<Vector<String>> datas = new Vector<Vector<String>>();
			datas = (Vector<Vector<String>>) gDatas.clone();
			DefaultTableModel model = new DefaultTableModel(){
				private static final long serialVersionUID = 1L;
				@Override
				public boolean isCellEditable(int row, int column) {
					return false;
				}
			};
			model.setDataVector(datas, tableHeaders);
			table.setModel(model);
			Utils.setTableColumnWidth(tableHeaders, table);
		}
	}
	
	@SuppressWarnings("unchecked")
	private void filterDataByCheckBox() {
		Vector<Vector<String>> ckData = new Vector<Vector<String>>();
		for(Vector<String> v : gDatas) {
			if(ccName.contains(v.get(0).toString().charAt(0)+"")) {
				ckData.add(v);
			}
		}
		if (ckData.isEmpty() &&
		   (!ck01.isSelected() && !ck02.isSelected() && !ck03.isSelected() &&
			!ck04.isSelected() && !ck05.isSelected() && !ck06.isSelected())) {
			ckData = (Vector<Vector<String>>) gDatas.clone();
		}
		((DefaultTableModel)table.getModel()).getDataVector().clear();
		DefaultTableModel model = new DefaultTableModel(){
			private static final long serialVersionUID = 1L;
			@Override
			public boolean isCellEditable(int row, int column) {
				return false;
			}
		};
		model.setDataVector(ckData, tableHeaders);
		table.setModel(model);
		Utils.setTableColumnWidth(tableHeaders, table);
	}
	
	private void sendQueryTicketRequest(String url) throws HttpException, IOException {
		HttpGet get = new HttpGet(url);
		CloseableHttpResponse response = Utils.getHttpClient().execute(get);
		int statusCode = response.getStatusLine().getStatusCode();
		String result = "";
		if (statusCode == HttpStatus.SC_OK) {
            System.out.println("查票成功.");
            result = EntityUtils.toString(response.getEntity());
        }else {
            System.out.println("查票失敗,url="+url+",statusCode="+statusCode);
            return;
        }
		JSONObject obj = JSON.parseObject(result);
		JSONArray array = obj.getJSONObject("data").getJSONArray("result");
		int len = array.size();
		//獲取車次信息在3號位置,始發站信息在6號位置,終點站信息在7號位置,出發時間在8號位置,抵達時間在9號位置
		//經歷時間在10號位置,特別注意,商務/特等座在32或25位置,一等座信息在31號位置,二等座信息在30號位置
		//高級軟臥信息在21號位置,軟臥信息在23號位置,動臥信息在27號位置,硬臥信息在28號位置
		//軟座信息在24號位置,硬座信息在29號位置,無座信息在26號位置,其他信息在22號位置,備註信息在1號位置
		gDatas.clear();
		for(int i = 0; i < len; i++) {
			Vector<String> row = new Vector<String>();
			String[] resultData = array.get(i).toString().split("\\|");
			//收集數據
			colloctionData(row, resultData);
		}
		//填充數據
		fillData2Table();
		//根據複選框過濾數據
		if (ck01.isSelected() || ck02.isSelected() || ck03.isSelected() ||
			ck04.isSelected() || ck05.isSelected() || ck06.isSelected()) {
			filterDataByCheckBox();
		}
		//給數據添加背景色
		Utils.setBackgoundColorForTable(table);
		//添加行點擊監聽
		addTableRowListener(table);
		
		obj.clear();
	}
	
	private void addQueryMListener(JMenu menu) {
		menu.addMouseListener(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent e) {
			}
			@Override
			public void mousePressed(MouseEvent e) {
			}
			@Override
			public void mouseExited(MouseEvent e) {
			}
			@Override
			public void mouseEntered(MouseEvent e) {
			}
			@Override
			public void mouseClicked(MouseEvent e) {
				try {
					sendQueryPassengersRequest();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
	}
	
	private void sendQueryPassengersRequest() throws ClientProtocolException, IOException {
		HttpPost post = new HttpPost(Utils.queryPassengersUrl);
		List<NameValuePair> formPair = new ArrayList<NameValuePair>();
	    formPair.add(new BasicNameValuePair("pageIndex", "1"));
	    formPair.add(new BasicNameValuePair("pageSize", "15"));
	    UrlEncodedFormEntity urlEntity = new UrlEncodedFormEntity(formPair, "UTF-8");
	    post.setEntity(urlEntity);
	    Utils.setPostRequestHeaders(post);
	    CloseableHttpResponse response;
	    response = Utils.getHttpClient().execute(post);
    	int respCode = response.getStatusLine().getStatusCode();
    	if(respCode == HttpStatus.SC_OK) {
    		JSONObject obj = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
    		if(Integer.parseInt(obj.getString("httpstatus")) == 200) {
    			System.out.println("獲取聯繫人成功");
    			System.out.println(obj.toString());
    		}else {
    			System.out.println("獲取聯繫人失敗");
    		}
    	}else {
    		System.out.println("獲取聯繫人失敗");
    	}
	}

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					My12307 frame = new My12307();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
}
package my12307;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class LoginDialog extends JDialog{
	
	private static final long serialVersionUID = 1L;
	private JTextField userField;
	private JPasswordField pswdField;
	private JPanel imagePanel;
	private JLabel imageLabel;
	private Icon icon;
	private int X = 10;
	private int Y = 15;
	private JLayeredPane layeredPane = new JLayeredPane();;
	private StringBuffer callback = new StringBuffer("jQuery19107521990954709705_");
	private String random = "";
	private String random2 = "";
	private String yzmAnswer;
	
	private void initFrame(JFrame parent) throws ClientProtocolException, IOException{
		
		userField = new JTextField(15);
		pswdField = new JPasswordField(15);
		JLabel userLabel = new JLabel("用戶名:");
		JLabel pswdLabel = new JLabel("密    碼::");
		JButton loginButton = new JButton("登錄");
		JButton cancelButton = new JButton("取消");
		addLoginButtonListener(loginButton);
		addCancelButtonListener(cancelButton);
		JPanel inputPanel = new JPanel(new GridLayout(2, 2, -90, 15));
		JPanel buttonPanel = new JPanel(new GridLayout(1, 2, 10, 0));
		imagePanel = new JPanel(new GridLayout(1, 1, 10, 0));
		
		inputPanel.add(userLabel);
		inputPanel.add(userField);
		inputPanel.add(pswdLabel);
		inputPanel.add(pswdField);
		inputPanel.setBorder(BorderFactory.createEmptyBorder(X, Y, 10, 15));
		
		buttonPanel.add(loginButton);
		buttonPanel.add(cancelButton);
		buttonPanel.setBorder(BorderFactory.createEmptyBorder(X, Y, 10, 15));
		
		setLayout(new BorderLayout());
		getContentPane().add(inputPanel, BorderLayout.NORTH);
		getContentPane().add(buttonPanel, BorderLayout.CENTER);
		
		getYzmBindListener();
		
		int parentX = parent.getX();
		int parentY = parent.getY();
		int parentWidth = (int)parent.getWidth();
		int parentHeight = (int)parent.getHeight();
		
		int childWidth = 280;
		int childHight = 300;
		int childX = parentX + parentWidth/2 - childWidth/2;
		int childY = parentY + parentHeight/2 - childHight/2;
		setBounds(childX, childY, childWidth, childHight);
		setTitle("登錄");
		setResizable(false);
		pack();
		
		YzmUtils.initYzm(layeredPane);
	}
	
	public LoginDialog(JFrame parent) throws ClientProtocolException, IOException {
		super(parent, true);
		setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		if(Utils.cookieStore.getCookies().size() == 0) {
			try {
				Utils.initLogin();
				Utils.initRail();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		initFrame(parent);
	}
	
	private void clearYzmPanel(){
		YzmUtils.yzm1 = 0;
		YzmUtils.yzm2 = 0;
		YzmUtils.yzm3 = 0;
		YzmUtils.yzm4 = 0;
		YzmUtils.yzm5 = 0;
		YzmUtils.yzm6 = 0;
		YzmUtils.yzm7 = 0;
		YzmUtils.yzm8 = 0;
		
		imagePanel.removeAll();
		layeredPane.removeAll();
	}
	
	@SuppressWarnings("deprecation")
	//獲取驗證碼圖片並綁定點擊驗證碼事件
	private void getYzmBindListener() throws ClientProtocolException, IOException {
		clearYzmPanel();
		String image = getYzmImage();
		imageLabel = new JLabel();
		icon = new ImageIcon(image);
		imageLabel.setIcon(icon);
		addLabelListener(imageLabel);//監聽驗證碼點擊事件
		imagePanel.add(imageLabel);
		imagePanel.setBounds(0, 0, icon.getIconWidth(), icon.getIconHeight());
		
		Dimension dimension = new Dimension(icon.getIconWidth(), icon.getIconHeight());
		layeredPane.setPreferredSize(dimension);
		layeredPane.add(imagePanel, new Integer(0));
		getContentPane().add(layeredPane, BorderLayout.SOUTH);
		
		YzmUtils.initYzm(layeredPane);
	}

	private void addLabelListener(JLabel imageLbel) {
		imageLbel.addMouseListener(new MouseListener() {
			@Override
			public void mouseReleased(MouseEvent e) {
			}
			@Override
			public void mousePressed(MouseEvent e) {
			}
			@Override
			public void mouseExited(MouseEvent e) {
			}
			@Override
			public void mouseEntered(MouseEvent e) {
			}
			@Override
			public void mouseClicked(MouseEvent e) {
				YzmUtils.addSign2Yzm(e);
			}
		});
	}

	private void addCancelButtonListener(JButton cancelButton) {
		cancelButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				LoginDialog.this.dispose();
			}
		});
	}
	
	private String login12306(String username, String password) throws IOException {
		String uamtk = "";
		HttpPost post = new HttpPost(Utils.loginUrl);
		List<NameValuePair> formPair = new ArrayList<NameValuePair>();
	    formPair.add(new BasicNameValuePair("username", username));
	    formPair.add(new BasicNameValuePair("password", password));
	    formPair.add(new BasicNameValuePair("appid", "otn"));
	    formPair.add(new BasicNameValuePair("answer", yzmAnswer));
	    UrlEncodedFormEntity urlEntity = new UrlEncodedFormEntity(formPair, "UTF-8");
	    post.setEntity(urlEntity);
	    Utils.setPostRequestHeaders(post);
	    CloseableHttpResponse response;
	    
	    int respCode = 0;
	    int loop = 5;
	    while(loop > 0) {
	    	response = Utils.getHttpClient().execute(post);
	    	respCode = response.getStatusLine().getStatusCode();
	    	JSONObject obj = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
	    	if(respCode == HttpStatus.SC_OK) {
	    		if("0".equals(obj.getString("result_code"))) {
	    			System.out.println("登錄成功,result_code:"+respCode+"result_message:"+
	    					obj.getString("result_message")+"uamtk:"+obj.getString("uamtk"));
	    			uamtk = obj.getString("uamtk");
	    			this.setVisible(false);
	    		    return uamtk;
	    		}else {
	    			System.out.println("登錄失敗,result_code="+obj.getString("result_code")+",result_message:"+obj.getString("result_message"));
		    		//getYzmBindListener();
	    			break;
	    		}
	    		
	    	}else if(respCode == HttpStatus.SC_MOVED_TEMPORARILY){
	    		System.out.println("請求登錄重定向,Location:"+response.getFirstHeader("Location").getValue());
	    		//getYzmBindListener();
	    		loop--;
	    	}else {
	    		System.out.println("登錄失敗,respCode="+respCode+",result_message:"+obj.getString("result_message"));
	    		//getYzmBindListener();
	    		break;
	    	}
	    }
	    getYzmBindListener();
	    return uamtk;
	}
	
	private void addLoginButtonListener(JButton loginButton) {
		loginButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				
				//校驗驗證碼url爲:https://kyfw.12306.cn/passport/captcha/captcha-check
				yzmAnswer = YzmUtils.getYzmAnswer();
				if ("".equals(yzmAnswer)) {
					System.out.println("請先選擇驗證碼後再登錄");
					return;
				}
				random2 = String.valueOf(Long.parseLong(random2)+1);
				String checkYzmUrl = Utils.checkYzmUrl+"callback="+callback+
						"&answer="+yzmAnswer+"&rand=sjrand&login_site=E&_="+random2;
				System.out.println("校驗驗證碼的url:"+checkYzmUrl);
				HttpGet get = new HttpGet(checkYzmUrl);
				Utils.setGetRequestHeaders(get);
	            // 通過請求對象獲取響應對象
	            String[] res = null;
	            String result = "";
	            CloseableHttpResponse response;
				try {
					response = Utils.getHttpClient().execute(get);
					int respCode = response.getStatusLine().getStatusCode();
					HttpEntity entity = null;
		            if (respCode == HttpStatus.SC_OK) {
		            	entity = response.getEntity();
		            	result = EntityUtils.toString(entity);
		            	System.out.println("result:"+result);
		            	res = result.split("\"");
		            }else {
		            	System.out.println("驗證失敗,statusCode="+respCode);
		            	getYzmBindListener();
		            }
		            if ("4".contentEquals(res[7])) {
		            	System.out.println("驗證成功,result_message="+res[3]);
		            	String username = userField.getText();
						String password = new String(pswdField.getPassword());
						//saveCookies();
						String uamtk = login12306(username, password);
						if(!"".equals(uamtk)) {
							sendGetUamTkRequest();
						}
		            }else {
		            	System.out.println("驗證失敗,result_message="+res[3]);
		            	getYzmBindListener();
		            }
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
	}
	
	private void sendGetUamTkRequest() throws ClientProtocolException, IOException {
		HttpPost post = new HttpPost(Utils.getUamTk);
		List<NameValuePair> formPair = new ArrayList<NameValuePair>();
	    formPair.add(new BasicNameValuePair("appid", "otn"));
	    UrlEncodedFormEntity urlEntity = new UrlEncodedFormEntity(formPair, "UTF-8");
	    post.setEntity(urlEntity);
	    Utils.setPostRequestHeaders(post);
	    CloseableHttpResponse response;
	    response = Utils.getHttpClient().execute(post);
    	int respCode = response.getStatusLine().getStatusCode();
    	JSONObject obj = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
    	if(respCode == HttpStatus.SC_OK) {
    		System.out.println("獲取uamtk成功,result_code:"+respCode+"result_message:"+
    				obj.getString("result_message")+"newapptk:"+obj.getString("newapptk"));
    		String newAppTk = obj.getString("newapptk");
    		sendUamAuthClientRequest(newAppTk);
    	}else {
    		System.out.println("獲取uamtk失敗,respCode="+respCode+"result_message:"+obj.getString("result_message"));
    	}
	}
	
	private void sendUamAuthClientRequest(String newAppTk) throws ClientProtocolException, IOException {
		HttpPost post = new HttpPost(Utils.uamAuthClient);
		List<NameValuePair> formPair = new ArrayList<NameValuePair>();
	    formPair.add(new BasicNameValuePair("tk", newAppTk));
	    UrlEncodedFormEntity urlEntity = new UrlEncodedFormEntity(formPair, "UTF-8");
	    post.setEntity(urlEntity);
	    Utils.setPostRequestHeaders(post);
	    CloseableHttpResponse response;
	    response = Utils.getHttpClient().execute(post);
    	int respCode = response.getStatusLine().getStatusCode();
    	JSONObject obj = JSONObject.parseObject(EntityUtils.toString(response.getEntity()));
    	if(respCode == HttpStatus.SC_OK) {
    		System.out.println("uamAuth成功,result_code:"+respCode+"result_message:"+obj.getString("result_message")+
    			"newapptk:"+obj.getString("newapptk")+"username:"+obj.getString("username"));
    		//saveCookies();
    	}else {
    		System.out.println("uamAuth失敗,respCode="+respCode+"result_message:"+obj.getString("result_message"));
    	}
	}
	
	private String getYzmImage() throws ClientProtocolException, IOException {
	    random = String.valueOf(System.currentTimeMillis());
	    random2 = random;
	    random2 = String.valueOf(Long.parseLong(random2)+1);
		callback.append(random);
		
		String getYzmUrl = Utils.getYzmUrl+"login_site=E&module=login&rand=sjrand&"
				+random+"callback="+callback+"&_="+random2;
		System.out.println("請求驗證碼的url:"+getYzmUrl);
		HttpGet getMethod = new HttpGet(getYzmUrl);
		Utils.setGetRequestHeaders(getMethod);
		CloseableHttpClient client = Utils.getHttpClient();
		Utils.printCookies();
		CloseableHttpResponse response = client.execute(getMethod);
		HttpEntity entity = null;
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode == HttpStatus.SC_OK) {
			entity = response.getEntity();
			System.out.println("獲取驗證碼成功.");
		}else {
			System.out.println("獲取驗證碼失敗,url="+getYzmUrl+",statusCode="+statusCode);
			return "";
		}
		
		JSONObject obj = JSON.parseObject(EntityUtils.toString(entity));
		Decoder decoder = Base64.getDecoder();
		try {  
            //Base64解碼  
			byte[] b = decoder.decode(obj.getString("image"));
            for(int i = 0; i < b.length; ++i){  
                if(b[i] < 0){//調整異常數據  
                    b[i] += 256;  
                }  
            }  
            //生成jpg圖片  
            String imgFilePath = "yzm/yzm_"+random+".jpg";//新生成的圖片  
            OutputStream out = new FileOutputStream(imgFilePath);      
            out.write(b);  
            out.flush();  
            out.close();  
            return imgFilePath;
        } catch (Exception e){  
        }
		obj.clear();
		return "";
	}
}

package my12307;

import java.awt.Color;
import java.awt.Component;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;

import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class Utils {

	static CookieStore cookieStore = new BasicCookieStore();
	static CloseableHttpClient httpClient = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
	
	static String accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
	static String acceptEncoding = "gzip, deflate, br";
	static String acceptLanguage = "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2";
	static String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:68.0) Gecko/20100101 Firefox/68.0";
	
	//url
	static String getStationUrl = "https://kyfw.12306.cn/otn/resources/js/framework/station_name.js";
	static String queryTicketsUrl = "https://kyfw.12306.cn/otn/leftTicket/query?";
	static String getRailUrl = "https://kyfw.12306.cn/otn/HttpZF/logdevice"+
			//"?algID=8iIPwpB28l"+
			"?algID=XWptt1kXbs"+
			//"&hashCode=XQTW18RSf_dOYnqpGaj_yA-WKSsKbH77QE7zN-cCdB0"+
			"&hashCode=K7H-SogpeC4-tIYLqCXJabQWEnBXNROVnaPuQXU8Vec"+
			"&FMQw=0"+
			"&q4f3=zh-CN"+
			"&VPIf=1"+
			"&custID=133"+
			"&VEek=unknown"+
			"&dzuS=0"+
			"&yD16=0"+
			"&EOQP=89f60554e6cb588cf7dcc391a91488a1"+
			"&lEnu=176525634"+
			"&jp76=52d67b2a5aa5e031084733d5006cc664"+
			"&hAqN=Win32"+
			"&platform=WEB"+
			"&ks0Q=d22ca0b81584fbea62237b14bd04c866"+
			"&TeRS=1010x1680"+
			"&tOHY=24xx1050x1680"+
			"&Fvje=i1l1o1s1"+
			"&q5aJ=-8"+
			"&wNLf=99115dfb07133750ba677d055874de87"+
			"&0aew=Mozilla/5.0%20(Windows%20NT%2010.0;%20Win64;%20x64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/76.0.3809.100%20Safari/537.36"+
			"&E3gR=a54e6d6499e595ae2cfaf80eda685cc2"+
			"&timestamp="+String.valueOf(System.currentTimeMillis());
	static String initUrl = "https://kyfw.12306.cn/otn/login/init";
	static String loginUrl = "https://kyfw.12306.cn/passport/web/login";
	static String logoutUrl = "https://kyfw.12306.cn/otn/login/conf";
	static String logoutUamtk = "https://kyfw.12306.cn/passport/web/auth/uamtk-static";
	static String getYzmUrl = "https://kyfw.12306.cn/passport/captcha/captcha-image64?";
	static String checkYzmUrl = "https://kyfw.12306.cn/passport/captcha/captcha-check?";
	static String getUamTk = "https://kyfw.12306.cn/passport/web/auth/uamtk";
	static String uamAuthClient = "https://kyfw.12306.cn/otn/uamauthclient";
	static String queryPassengersUrl = "https://kyfw.12306.cn/otn/passengers/query";
	
	static CloseableHttpClient getHttpClient() {
		return httpClient;
	}
	
	static CookieStore getCookieStore() {
		return cookieStore;
	}
	
	static void addRailCookies(String exp, String dfp) {
		BasicClientCookie expCookie = new BasicClientCookie("RAIL_EXPIRATION", exp);
        expCookie.setDomain("kyfw.12306.cn");
        expCookie.setPath("/");
        cookieStore.addCookie(expCookie);
        BasicClientCookie dfpCookie = new BasicClientCookie("RAIL_DEVICEID", dfp);
        dfpCookie.setDomain("kyfw.12306.cn");
        dfpCookie.setPath("/");
        cookieStore.addCookie(dfpCookie);
	}
	
	static void setGetRequestHeaders(HttpGet get) {
		get.addHeader("Accept",Utils.accept);
		get.addHeader("Accept-Encoding", Utils.acceptEncoding);
		get.addHeader("Accept-Language", Utils.acceptLanguage);
		get.addHeader("User-Agent",Utils.userAgent);
	}
	
	static void setPostRequestHeaders(HttpPost post) {
		post.addHeader("Accept",Utils.accept);
		post.addHeader("Accept-Encoding", Utils.acceptEncoding);
		post.addHeader("Accept-Language", Utils.acceptLanguage);
		post.addHeader("User-Agent",Utils.userAgent);
	}
	
	static void initLogin() throws ClientProtocolException, IOException {
		HttpGet getMethod = new HttpGet(Utils.initUrl);
		Utils.setGetRequestHeaders(getMethod);
		CloseableHttpResponse response = Utils.getHttpClient().execute(getMethod);
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode == HttpStatus.SC_OK) {
            System.out.println("初始化12306成功.");
            Utils.printCookies();
        }else {
            System.out.println("初始化12306失敗,url="+Utils.initUrl+",statusCode="+statusCode);
            return;
        }
	}

	static void initRail() throws ClientProtocolException, IOException {
		//獲取RAIL_DEVICEID和RAIL_EXPIRATION
		//String getJsUrl = "https://kyfw.12306.cn/otn/HttpZF/GetJS";
		HttpGet get = new HttpGet(Utils.getRailUrl);
		Utils.setGetRequestHeaders(get);
		CloseableHttpResponse response = Utils.getHttpClient().execute(get);
		int statusCode = response.getStatusLine().getStatusCode();
		if (statusCode == HttpStatus.SC_OK) {
            System.out.println("GetJS成功.");
            Utils.printCookies();
            String resStr = EntityUtils.toString(response.getEntity());
            String str = resStr.substring(resStr.indexOf("{"),resStr.indexOf("}")+1);
            System.out.println(str);
            JSONObject obj = JSON.parseObject(str);
            Utils.addRailCookies(obj.getString("exp"), obj.getString("dfp"));
            obj.clear();
        }else {
            System.out.println("GetJS失敗,url="+Utils.getRailUrl+",statusCode="+statusCode);
            return;
        }
	}
	
	static void printCookies() {
		System.out.println("打印cookie信息:");
		List<org.apache.http.cookie.Cookie> cs = Utils.getCookieStore().getCookies();
		for (int i = 0; i < cs.size(); i++) {
			System.out.println(cs.get(i).getName()+":"+cs.get(i).getValue());
		}
	}
	
	static void clearCookies() {
		System.out.println("清空cookie信息");
		cookieStore.clear();
	}
	
	static void putStation2Map(String result, HashMap<String, String> cityMap) {
		int startIdx = result.indexOf("'");
		int endIdx = result.length();
		String city = result.substring(startIdx, endIdx);
		String[] c = city.split("@");
		for(int i = 1; i < c.length; i++) {
			String[] cc = c[i].split("\\|");
			cityMap.put(cc[1], cc[2]);
		}
	}
	
	static String getKeyFromMap(HashMap<String, String> map, String value) {
		for(String getKey: map.keySet()) {
			if(map.get(getKey).equals(value)) {
				return getKey;
			}
		}
		return "";
	}
	
	static void setTableColumnWidth(Vector<String> tableHeaders, JTable table) {
		table.getColumn(tableHeaders.get(1)).setPreferredWidth(55);
		table.getColumn(tableHeaders.get(2)).setPreferredWidth(55);
		table.getColumn(tableHeaders.get(7)).setPreferredWidth(55);
		table.getColumn(tableHeaders.get(8)).setPreferredWidth(55);
		table.getColumn(tableHeaders.get(9)).setPreferredWidth(60);
		table.getColumn(tableHeaders.get(10)).setPreferredWidth(45);
		table.getColumn(tableHeaders.get(11)).setPreferredWidth(45);
		table.getColumn(tableHeaders.get(12)).setPreferredWidth(45);
		table.getColumn(tableHeaders.get(13)).setPreferredWidth(45);
		table.getColumn(tableHeaders.get(14)).setPreferredWidth(45);
		table.getColumn(tableHeaders.get(15)).setPreferredWidth(45);
		table.getColumn(tableHeaders.get(16)).setPreferredWidth(45);
	}
	
	static void setBackgoundColorForTable(JTable table) {
		DefaultTableCellRenderer tcr = new DefaultTableCellRenderer() {
			private static final long serialVersionUID = 1L;
			@Override
			public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
					boolean hasFocus, int row, int column) {
				//return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
				JButton button;
				JPanel panel;
				Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
				if (row % 2 == 0) {
					setBackground(Color.white); //設置奇數行底色
				}
				else if (row % 2 == 1) {
					setBackground(new Color(238,241,248)); //設置偶數行底色
				}
				//設置'有'和'無'的顏色
				if (value != null && column >= 6 && column <= 16) {
					if("--".equals(value.toString()) || "無".equals(value.toString())) {
						setForeground(new Color(153,153,153));
					}else if("有".equals(value.toString())) {
						setForeground(new Color(38,163,6));
					}else { //數字
						setForeground(Color.black);
					}
				}else {
					setForeground(Color.black);
				}
				
				//添加預定按鈕
				if (column == 17) {
					Object obj6 = table.getModel().getValueAt(row, 6);
					Object obj7 = table.getModel().getValueAt(row, 7);
					Object obj8 = table.getModel().getValueAt(row, 8);
					Object obj9 = table.getModel().getValueAt(row, 9);
					Object obj10 = table.getModel().getValueAt(row, 10);
					Object obj11 = table.getModel().getValueAt(row, 11);
					Object obj12 = table.getModel().getValueAt(row, 12);
					Object obj13 = table.getModel().getValueAt(row, 13);
					Object obj14 = table.getModel().getValueAt(row, 14);
					Object obj15 = table.getModel().getValueAt(row, 15);
					
					if ( (obj6 != null) && (!"--".equals(obj6.toString())) && (!"無".equals(obj6.toString())) && 
							(("有".equals(obj6.toString())) || (Integer.parseInt(obj6.toString()) > 0)) || 
						 (obj7 != null) && (!"--".equals(obj7.toString())) && (!"無".equals(obj7.toString())) && 
							(("有".equals(obj7.toString())) || (Integer.parseInt(obj7.toString()) > 0)) || 
						 (obj8 != null) && (!"--".equals(obj8.toString())) && (!"無".equals(obj8.toString())) && 
							(("有".equals(obj8.toString())) || (Integer.parseInt(obj8.toString()) > 0)) || 
						 (obj9 != null) && (!"--".equals(obj9.toString())) && (!"無".equals(obj9.toString())) && 
							(("有".equals(obj9.toString())) || (Integer.parseInt(obj9.toString()) > 0)) ||
						 (obj10 != null) && (!"--".equals(obj10.toString())) && (!"無".equals(obj10.toString())) && 
							(("有".equals(obj10.toString())) || (Integer.parseInt(obj10.toString()) > 0)) || 
						 (obj11 != null) && (!"--".equals(obj11.toString())) && (!"無".equals(obj11.toString())) && 
							(("有".equals(obj11.toString())) || (Integer.parseInt(obj11.toString()) > 0)) || 
						 (obj12 != null) && (!"--".equals(obj12.toString())) && (!"無".equals(obj12.toString())) && 
							(("有".equals(obj12.toString())) || (Integer.parseInt(obj12.toString()) > 0)) || 
						 (obj13 != null) && (!"--".equals(obj13.toString())) && (!"無".equals(obj13.toString())) && 
							(("有".equals(obj13.toString())) || (Integer.parseInt(obj13.toString()) > 0)) || 
						 (obj14 != null) && (!"--".equals(obj14.toString())) && (!"無".equals(obj14.toString())) && 
							(("有".equals(obj14.toString())) || (Integer.parseInt(obj14.toString()) > 0)) || 
						 (obj15 != null) && (!"--".equals(obj15.toString())) && (!"無".equals(obj15.toString())) && 
							(("有".equals(obj15.toString())) || (Integer.parseInt(obj15.toString()) > 0)) ){
						panel = new JPanel();
						button = new JButton();
						button.setText("預定");
						button.setForeground(Color.white);
						button.setBackground(new Color(0,119,255));
						panel.add(button, SwingConstants.CENTER);
						return panel;
					}else {
						setForeground(new Color(153,153,153));
						setValue("預定");
					}
				}
				
				return cell;
			}
		};
		tcr.setHorizontalAlignment(SwingConstants.CENTER);
		table.setDefaultRenderer(Object.class, tcr);
	}
}

package my12307;

import java.awt.event.MouseEvent;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

public class YzmUtils {
	
	private static String signImage = "src//sign.png";
	public static int yzm1 = 0;
	public static int yzm2 = 0;
	public static int yzm3 = 0;
	public static int yzm4 = 0;
	public static int yzm5 = 0;
	public static int yzm6 = 0;
	public static int yzm7 = 0;
	public static int yzm8 = 0;
	private final static int YZM_1 = 1;
	private final static int YZM_2 = 2;
	private final static int YZM_3 = 3;
	private final static int YZM_4 = 4;
	private final static int YZM_5 = 5;
	private final static int YZM_6 = 6;
	private final static int YZM_7 = 7;
	private final static int YZM_8 = 8;
	private static JPanel yzmPanel1;
	private static JPanel yzmPanel2;
	private static JPanel yzmPanel3;
	private static JPanel yzmPanel4;
	private static JPanel yzmPanel5;
	private static JPanel yzmPanel6;
	private static JPanel yzmPanel7;
	private static JPanel yzmPanel8;
	private static String yzm1Point = "35,72,";
	private static String yzm2Point = "111,72,";
	private static String yzm3Point = "181,72,";
	private static String yzm4Point = "250,72,";
	private static String yzm5Point = "35,148,";
	private static String yzm6Point = "111,148,";
	private static String yzm7Point = "181,148,";
	private static String yzm8Point = "250,148,";
	
	@SuppressWarnings("deprecation")
	static void initYzm(JLayeredPane layeredPane){
		yzmPanel1 = initSignImage(24, 55);
		yzmPanel2 = initSignImage(94, 55);
		yzmPanel3 = initSignImage(164, 55);
		yzmPanel4 = initSignImage(240, 55);
		yzmPanel5 = initSignImage(24, 130);
		yzmPanel6 = initSignImage(94, 130);
		yzmPanel7 = initSignImage(164, 130);
		yzmPanel8 = initSignImage(240, 130);
		
		layeredPane.add(yzmPanel1, new Integer(1));
		layeredPane.add(yzmPanel2, new Integer(1));
		layeredPane.add(yzmPanel3, new Integer(1));
		layeredPane.add(yzmPanel4, new Integer(1));
		layeredPane.add(yzmPanel5, new Integer(1));
		layeredPane.add(yzmPanel6, new Integer(1));
		layeredPane.add(yzmPanel7, new Integer(1));
		layeredPane.add(yzmPanel8, new Integer(1));
		yzmPanel1.setVisible(false);//表示驗證碼沒有選中
		yzmPanel2.setVisible(false);
		yzmPanel3.setVisible(false);
		yzmPanel4.setVisible(false);
		yzmPanel5.setVisible(false);
		yzmPanel6.setVisible(false);
		yzmPanel7.setVisible(false);
		yzmPanel8.setVisible(false);
	}
	
	static JPanel initSignImage(int x, int y) {
		JPanel panel = new JPanel();
		JLabel signLabel = new JLabel();
		Icon signIcon = new ImageIcon(signImage);
		signLabel.setIcon(signIcon);
		
		panel.setOpaque(false);
		panel.add(signLabel);
		panel.setBounds(x, y, signIcon.getIconWidth(), signIcon.getIconHeight());
		return panel;
	}
	
	static void setYzmIndexVisiable(JPanel panel, int yzm) {
		if(yzm%2 == 0) {  //表示驗證碼沒有選中
			panel.setVisible(true);
		} else {
			panel.setVisible(false);
		}
	}
	
	static void setYzmsVisiable(int index) {
		switch (index) {
		case YZM_1:
			setYzmIndexVisiable(yzmPanel1, yzm1);
			yzm1++;
			break;
		case YZM_2:
			setYzmIndexVisiable(yzmPanel2, yzm2);
			yzm2++;
			break;
		case YZM_3:
			setYzmIndexVisiable(yzmPanel3, yzm3);
			yzm3++;
			break;
		case YZM_4:
			setYzmIndexVisiable(yzmPanel4, yzm4);
			yzm4++;
			break;
		case YZM_5:
			setYzmIndexVisiable(yzmPanel5, yzm5);
			yzm5++;
			break;
		case YZM_6:
			setYzmIndexVisiable(yzmPanel6, yzm6);
			yzm6++;
			break;
		case YZM_7:
			setYzmIndexVisiable(yzmPanel7, yzm7);
			yzm7++;
			break;
		case YZM_8:
			setYzmIndexVisiable(yzmPanel8, yzm8);
			yzm8++;
			break;
		default:
			break;
		}
	}
	
	static String getYzmAnswer() {
		StringBuffer yzmAnswer = new StringBuffer();
		
		if (yzm1%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm1Point);
		}
		if (yzm2%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm2Point);
		}
		if (yzm3%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm3Point);
		}
		if (yzm4%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm4Point);
		}
		if (yzm5%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm5Point);
		}
		if (yzm6%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm6Point);
		}
		if (yzm7%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm7Point);
		}
		if (yzm8%2 == 1) { //該驗證碼被選中
			yzmAnswer.append(yzm8Point);
		}
		
		if (yzmAnswer.length() == 0) {
			System.out.println("請選擇驗證碼");
			return "";
		}
		
		return (yzmAnswer.deleteCharAt(yzmAnswer.length() - 1)).toString();
	}
	
	static void addSign2Yzm(MouseEvent e) {
		//(5,41)  第一張驗證碼座標
		int top = 41;
		int gap = 5;
		int xUnit = 67;  //每一個小圖寬
		int yUnit = 67;  //每一個小圖寬
		int xPoint = e.getX();
		int yPoint = e.getY();
		if(gap <= xPoint && xPoint < (gap + xUnit)) {
			if ((gap + top) <= yPoint && yPoint < (gap + yUnit + top)) {
				setYzmsVisiable(YZM_1);
			}else if ((gap + yUnit + top) <= yPoint && yPoint < (2*(gap + yUnit) + top)){
				setYzmsVisiable(YZM_5);
			}
		}else if((gap + xUnit) <= xPoint && xPoint < (2*(gap + xUnit))) {
			if ((gap + top) <= yPoint && yPoint < (gap + yUnit + top)) {
				setYzmsVisiable(YZM_2);
			}else if ((gap + yUnit + top) <= yPoint && yPoint < (2*(gap + yUnit) + top)){
				setYzmsVisiable(YZM_6);
			}
		}else if((2*(gap + xUnit)) <= xPoint && xPoint < (3*(gap + xUnit))) {
			if ((gap + top) <= yPoint && yPoint < (gap + yUnit + top)) {
				setYzmsVisiable(YZM_3);
			}else if ((gap + yUnit + top) <= yPoint && yPoint < (2*(gap + yUnit) + top)){
				setYzmsVisiable(YZM_7);
			}
		}else if((3*(gap + xUnit)) <= xPoint && xPoint < (4*(gap + xUnit))){
			if ((gap + top) <= yPoint && yPoint < (gap + yUnit + top)) {
				setYzmsVisiable(YZM_4);
			}else if ((gap + yUnit + top) <= yPoint && yPoint < (2*(gap + yUnit) + top)){
				setYzmsVisiable(YZM_8);
			}
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章