1. 程式人生 > >Android-->將佈局檔案放在伺服器上,動態改變佈局。

Android-->將佈局檔案放在伺服器上,動態改變佈局。

目前在做專案時候有這樣的需求:佈局檔案的控制元件型別大致相同,例如某佈局檔案由GridView、ScrollView、TextView、Button四個控制元件組成,但是控制元件的擺放位置不同。因為擺放的方式很多,不可能把所有擺放方式都寫一個佈局檔案,因為這樣不利於迭代開發。這時候就想出能不能把佈局檔案放在伺服器上,當需要某佈局的時候,從伺服器下載佈局檔案儲存到儲存卡上,然後讀取儲存卡上的佈局檔案。

思路大致清除了,那麼現在開始進行可行性分析。

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
上面的程式碼太熟悉不過了,建立一個新Android工程,這玩意就已經寫好了!通過setContentView()方法,我們可以設定佈局檔案,但是這裡的引數是R檔案的佈局ID,如果是佈局檔案的路徑就好了,這樣就可以直接讀取SD卡的XML佈局檔案了!按住Ctrl+滑鼠左鍵,點選setContentView()進入:
    /**
     * Set the activity content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the activity.
     *
     * @param layoutResID Resource ID to be inflated.
     * 
     * @see #setContentView(android.view.View)
     * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
     */
    public void setContentView(int layoutResID) {
        getWindow().setContentView(layoutResID);
        initActionBar();
    }
從這裡我們可以看到,setContentView()方法呼叫了Window類裡的setContentView()方法,調來調去啊!繼續按住Ctrl+滑鼠左鍵,點選setContentView()進入:
    /**
     * Convenience for
     * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)}
     * to set the screen content from a layout resource.  The resource will be
     * inflated, adding all top-level views to the screen.
     *
     * @param layoutResID Resource ID to be inflated.
     * @see #setContentView(View, android.view.ViewGroup.LayoutParams)
     */
    public abstract void setContentView(int layoutResID);
花擦,這裡變成了抽象函式,在哪裡實現啊!不要驚慌,通過原始碼可以得知,Window類是一個抽象類,那麼它的實現應該是在子類中。那麼Window類有哪些子類?
/**
 * Abstract base class for a top-level window look and behavior policy.  An
 * instance of this class should be used as the top-level view added to the
 * window manager. It provides standard UI policies such as a background, title
 * area, default key processing, etc.
 *
 * <p>The only existing implementation of this abstract class is
 * android.policy.PhoneWindow, which you should instantiate when needing a
 * Window.  Eventually that class will be refactored and a factory method
 * added for creating Window instances without knowing about a particular
 * implementation.
 */
這是Window類原始碼的開頭說明,從中可以立馬看到PhoneWindow,對!沒錯就是它!在PhoneWindow中終於找到了它的具體實現!
    @Override
    public void setContentView(int layoutResID) {
        if (mContentParent == null) {
            installDecor();
        } else {
            mContentParent.removeAllViews();
        }
<span style="color:#ff0000;">         mLayoutInflater.inflate(layoutResID, mContentParent);
</span>         final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
    }
從標紅的程式碼,我們可以看到,佈局的ID是用在了該段程式碼,看到了inflate方法,我想大家應該不陌生,在BaseAdpter中經常會用到,用來填充佈局的!繼續按住Ctrl+滑鼠左鍵,點選inflate(....)進入:
    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        <code>R.layout.main_page</code>)
     * @param root Optional view to be the parent of the generated hierarchy.
     * @return The root View of the inflated hierarchy. If root was supplied,
     *         this is the root View; otherwise it is the root of the inflated
     *         XML file.
     */
    public View inflate(int resource, ViewGroup root) {
        return inflate(resource, root, root != null);
    }

繼續按住Ctrl+滑鼠左鍵,點選return中的inflate(....)進入:
    /**
     * Inflate a new view hierarchy from the specified xml resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param resource ID for an XML layout resource to load (e.g.,
     *        <code>R.layout.main_page</code>)
     * @param root Optional view to be the parent of the generated hierarchy (if
     *        <em>attachToRoot</em> is true), or else simply an object that
     *        provides a set of LayoutParams values for root of the returned
     *        hierarchy (if <em>attachToRoot</em> is false.)
     * @param attachToRoot Whether the inflated hierarchy should be attached to
     *        the root parameter? If false, root is only used to create the
     *        correct subclass of LayoutParams for the root view in the XML.
     * @return The root View of the inflated hierarchy. If root was supplied and
     *         attachToRoot is true, this is root; otherwise it is the root of
     *         the inflated XML file.
     */
    public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
        if (DEBUG) System.out.println("INFLATING from resource: " + resource);
<span style="color:#ff0000;">         XmlResourceParser parser = getContext().getResources().getLayout(resource);
</span>        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }
重點來了,看到標紅程式碼,我們可以看到佈局ID被getLayout方法作為引數使用,最後返回了XmlResourceParser這玩意,那麼它是啥?點選它進去看看:
/**
 * The XML parsing interface returned for an XML resource.  This is a standard
 * XmlPullParser interface, as well as an extended AttributeSet interface and
 * an additional close() method on this interface for the client to indicate
 * when it is done reading the resource.
 */
public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
    /**
     * Close this interface to the resource.  Calls on the interface are no
     * longer value after this call.
     */
    public void close();
}

wow,它是一個介面,而且是繼承自XmlPullParser,那麼XmlPullParser是什麼?檢視它的原始碼,這裡就不貼出原始碼的英文介紹,因為巴拉巴拉太長了!這裡只要知道,它是解析XML檔案要使用到的。到這裡,我想大概有思路了,因為Android是支援解析Xml檔案的,例如遊戲的配置檔案可以用XML檔案完成。如果我們能夠將SD卡上的佈局檔案轉成XmlPullParser的話就應該可以完成這種需求!

最後來看看inflate方法的最終實現程式碼:

/**
     * Inflate a new view hierarchy from the specified XML node. Throws
     * {@link InflateException} if there is an error.
     * <p>
     * <em><strong>Important</strong></em>   For performance
     * reasons, view inflation relies heavily on pre-processing of XML files
     * that is done at build time. Therefore, it is not currently possible to
     * use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
     * 
     * @param parser XML dom node containing the description of the view
     *        hierarchy.
     * @param root Optional view to be the parent of the generated hierarchy (if
     *        <em>attachToRoot</em> is true), or else simply an object that
     *        provides a set of LayoutParams values for root of the returned
     *        hierarchy (if <em>attachToRoot</em> is false.)
     * @param attachToRoot Whether the inflated hierarchy should be attached to
     *        the root parameter? If false, root is only used to create the
     *        correct subclass of LayoutParams for the root view in the XML.
     * @return The root View of the inflated hierarchy. If root was supplied and
     *         attachToRoot is true, this is root; otherwise it is the root of
     *         the inflated XML file.
     */
    public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            Context lastContext = (Context)mConstructorArgs[0];
            mConstructorArgs[0] = mContext;
            View result = root;

            try {
                // Look for the root node.
                int type;
                while ((type = parser.next()) != XmlPullParser.START_TAG &&
                        type != XmlPullParser.END_DOCUMENT) {
                    // Empty
                }

                if (type != XmlPullParser.START_TAG) {
                    throw new InflateException(parser.getPositionDescription()
                            + ": No start tag found!");
                }

                final String name = parser.getName();
                
                if (DEBUG) {
                    System.out.println("**************************");
                    System.out.println("Creating root view: "
                            + name);
                    System.out.println("**************************");
                }

                if (TAG_MERGE.equals(name)) {
                    if (root == null || !attachToRoot) {
                        throw new InflateException("<merge /> can be used only with a valid "
                                + "ViewGroup root and attachToRoot=true");
                    }

                    rInflate(parser, root, attrs, false);
                } else {
                    // Temp is the root view that was found in the xml
                    View temp;
                    if (TAG_1995.equals(name)) {
                        temp = new BlinkLayout(mContext, attrs);
                    } else {
                        temp = createViewFromTag(root, name, attrs);
                    }

                    ViewGroup.LayoutParams params = null;

                    if (root != null) {
                        if (DEBUG) {
                            System.out.println("Creating params from root: " +
                                    root);
                        }
                        // Create layout params that match root, if supplied
                        params = root.generateLayoutParams(attrs);
                        if (!attachToRoot) {
                            // Set the layout params for temp if we are not
                            // attaching. (If we are, we use addView, below)
                            temp.setLayoutParams(params);
                        }
                    }

                    if (DEBUG) {
                        System.out.println("-----> start inflating children");
                    }
                    // Inflate all children under temp
                    rInflate(parser, temp, attrs, true);
                    if (DEBUG) {
                        System.out.println("-----> done inflating children");
                    }

                    // We are supposed to attach all the views we found (int temp)
                    // to root. Do that now.
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }

                    // Decide whether to return the root that was passed in or the
                    // top view found in xml.
                    if (root == null || !attachToRoot) {
                        result = temp;
                    }
                }

            } catch (XmlPullParserException e) {
                InflateException ex = new InflateException(e.getMessage());
                ex.initCause(e);
                throw ex;
            } catch (IOException e) {
                InflateException ex = new InflateException(
                        parser.getPositionDescription()
                        + ": " + e.getMessage());
                ex.initCause(e);
                throw ex;
            } finally {
                // Don't retain static reference on context.
                mConstructorArgs[0] = lastContext;
                mConstructorArgs[1] = null;
            }

            return result;
        }
    }
最後通過該方法,就可以返回一個View,該View相當於整個佈局(因為佈局也是View)。通過返回的View,就可以進行findViewById的操作了!

關於從SD卡讀取XML檔案的網上例子有很多,下面專案中用到的方法,用來得到XmlPullParser。

	public XmlPullParser getXmlPullParser(String resource) {

		XmlPullParser parser = Xml.newPullParser();
		try {
			FileInputStream is = new FileInputStream(resource);
			parser.setInput(is, "utf-8");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return parser;
	}
這裡傳入的就是XML在SD卡中的路徑,通過相關操作就可以得到XmlPullParser物件。答題思路清晰明瞭,接下來說說如何做?

首先我們要把Android中的LayoutInflate類拷貝一份到自己工程中,接下來的工作就是照葫蘆畫瓢了!看下圖:


從上圖,可以看到LayoutInflate中的所有inflate方法,可惜就是沒有以String 作為引數的方法,那麼這裡我們就按照原始碼中inflate方法進行增加,如下:

	public View inflate(String resource, ViewGroup root) {
		return inflate(resource, root, root != null);
	}
接下來還有
	public View inflate(String resource, ViewGroup root, boolean attachToRoot) {
		XmlPullParser parser = getXmlPullParser(resource);
		return inflate(parser, root, attachToRoot);
	}

最後就可以調到系統原有的以XmlPullPaser作為引數的inflate方法。那麼這裡就完成了嗎?其實沒有,這裡做的操作僅僅只是讀取佈局檔案操作。裡面的控制元件如何識別,控制元件的屬性怎麼操作,都需要繼續研究。XML檔案裡面有佈局,也有控制元件,若SD卡上的XML檔案有某控制元件,那麼我們就要重寫該控制元件。因為這裡讀取佈局的邏輯是我們自己寫的,那麼相應的View的操作也要自己重寫。具體原因將在後續的某期部落格中進行分析。例如XML檔案中有Button控制元件:

        <Button
            android:id="@+id/btn_back"
            android:layout_width="@dimen/mine_back_btn_width"
            android:layout_height="@dimen/mine_back_btn_height"
            android:layout_gravity="center_vertical"
            android:background="@drawable/mine_btn_back" />
例如id,layout_width,layout_height等屬性,如果我們不重寫Button,那麼這些屬性都是無用的。因為我們沒有進行相應的操作,大家通過閱讀Button原始碼就可以瞭解AttributeSet的相關知識,有時間在後續部落格我也將進行分析。
public class VAButton extends android.widget.Button {


	public VAButton(Context context, AttributeSet attrs) {
		super(context);
		setAttributeSet(attrs);
	}

	@SuppressWarnings("deprecation")
	public void setAttributeSet(AttributeSet attrs) {

		HashMap<String, ParamValue> map = YDResource.getInstance().getViewMap();

		int count = attrs.getAttributeCount();
		for (int i = 0; i < count; i++) {
			ParamValue key = map.get(attrs.getAttributeName(i));
			if (key == null) {
				continue;
			}
			switch (key) {
			case id:
				this.setTag(attrs.getAttributeValue(i));
				break;
			case text:
				String value = YDResource.getInstance().getString(
						attrs.getAttributeValue(i));
				this.setText(value);
				break;
			case ellipsize:
				if (attrs.getAttributeBooleanValue(i, false)) {

					this.setFocusable(true);
					this.setFocusableInTouchMode(true);
					this.setSingleLine(true);
					this.setEllipsize(TruncateAt.MARQUEE);
					this.setMarqueeRepeatLimit(1000);
					this.setSingleLine();
					this.setHorizontallyScrolling(true);
					this.requestFocus();
				}
				break;
			case fadingEdge:
				this.setHorizontalFadingEdgeEnabled(attrs
						.getAttributeBooleanValue(i, false));
				break;
			case scrollHorizontally:
				this.setHorizontallyScrolling(attrs.getAttributeBooleanValue(i,
						false));
				break;
			case textColor:
				this.setTextColor(YDResource.getInstance().getIntColor(
						attrs.getAttributeValue(i)));
				break;
			case textSize:
				String val1 = attrs.getAttributeValue(i);
				if (!TextUtils.isEmpty(val1)) {
					this.setTextSize(YDResource.getInstance()
							.calculateRealSize(val1));
				}
				break;
			case visibility:
				String val2 = attrs.getAttributeValue(i);
				if (!TextUtils.isEmpty(val2)) {
					if (val2.equals("invisible")) {
						this.setVisibility(View.INVISIBLE);
					} else if (val2.equalsIgnoreCase("gone")) {
						this.setVisibility(View.GONE);
					}
				}
				break;
			case background:
				String backgroundString = attrs.getAttributeValue(i);
				if (backgroundString.startsWith("#")) {
					this.setBackgroundColor(YDResource.getInstance()
							.getIntColor(attrs.getAttributeValue(i)));
				} else {
					if (backgroundString.startsWith("@drawable/")) {
						backgroundString = backgroundString.substring(10);
					}
					String rootpath = getContext().getFilesDir().toString();
					StringBuilder sb = new StringBuilder();
					sb.append(rootpath).append("/").append(backgroundString)
							.append(".png");

					Bitmap bm = BitmapFactory.decodeFile(sb.toString());
					setBackgroundDrawable(new BitmapDrawable(bm));
				}
				break;
			case textStyle:
				if ("bold".equalsIgnoreCase(attrs.getAttributeValue(i)))
					this.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
				break;
			case style:
				String style = attrs.getAttributeValue(i);
				style = style.substring(style.indexOf("/") + 1);

				Log.i("button", "設定屬性值");
				int id = YDResource.getInstance().getIdentifier(
						"R.style." + style);
				this.setTextAppearance(getContext(), id);
				break;
			case src:

				break;
			case contentDescription:
				String content = attrs.getAttributeValue(i);
				this.setContentDescription(content);
				break;
			case gravity:
				this.setGravity(Gravity.CENTER_HORIZONTAL);
				break;
			default:
				break;
			}
		}
	}

}
通過上面程式碼,我們可以知道,這裡的操作都是對各種屬性標籤利用程式碼來進行設定。如果有些複雜的屬性不想寫了,其實最後還是可以通過程式碼來完成的。這裡就是你的佈局需要多少控制元件屬性,就要在程式碼中完成多少屬性的設定。佈局控制元件的程式碼,以FrameLayout為例:
public class VAFrameLayout extends android.widget.FrameLayout {



	public VAFrameLayout(Context context, AttributeSet attrs) {
		super(context);
		setLayoutParams(generateLayoutParams(attrs));
	}

	@SuppressWarnings({ "unchecked", "deprecation" })
	@Override
	public LayoutParams generateLayoutParams(AttributeSet attrs) {
		// TODO Auto-generated method stub
		LayoutParams params = this.generateDefaultLayoutParams();
		HashMap<String, ParamValue> map = YDResource.getInstance()
				.getLayoutMap();
		params.width = -2;
		params.height = -2;
		int count = attrs.getAttributeCount();
		for (int i = 0; i < count; i++) {
			String name = attrs.getAttributeName(i);
			ParamValue key = map.get(name);
			if (key == null) {
				continue;
			}
			switch (key) {
			case layout_width:
				String width = attrs.getAttributeValue(i);
				if (width.startsWith("f") || width.startsWith("m")) {
					params.width = LayoutParams.MATCH_PARENT;
					break;
				}
				if (width.startsWith("w")) {
					params.width = LayoutParams.WRAP_CONTENT;
					break;
				}
				params.width = YDResource.getInstance()
						.calculateRealSize(width);
				break;
			case layout_height:
				String height = attrs.getAttributeValue(i);
				if (height.startsWith("f") || height.startsWith("m")) {
					params.width = -1;
					break;
				}
				if (height.startsWith("w")) {
					params.width = -2;
					break;
				}
				params.height = YDResource.getInstance().calculateRealSize(
						height);
				break;
			case layout_gravity:

				params.gravity = YDResource.getInstance().getGravity(
						attrs.getAttributeValue(i));

				break;
			case layout_marginLeft:
				params.leftMargin = YDResource.getInstance().calculateRealSize(
						attrs.getAttributeValue(i));
				break;
			case layout_margin:
				int tm = YDResource.getInstance().calculateRealSize(
						attrs.getAttributeValue(i));
				params.setMargins(tm, tm, tm, tm);
				break;

			default:
				break;
			}
		}
		return params;
	}

}

好了,今天的分析就到這裡!

..................................................................................................................................

文章中肯定有寫的不到位的,歡迎大家給出更好的思路。需要原始碼的可以留言,目前這部分操作已經打包成jar,可以在專案中使用。





相關推薦

Android-->佈局檔案放在伺服器動態改變佈局

目前在做專案時候有這樣的需求:佈局檔案的控制元件型別大致相同,例如某佈局檔案由GridView、ScrollView、TextView、Button四個控制元件組成,但是控制元件的擺放位置不同。因為擺放的方式很多,不可能把所有擺放方式都寫一個佈局檔案,因為這樣不利於迭代開發

androidpdf檔案轉換成Bitmapbitmap以圖片的 方式儲存到相簿

背景: 公司專案要求使用者可以在手機端檢視發票並將發票已圖片的形式儲存到相簿,以便列印,問題來了,因為發票是.pdf,android不支援直接檢視pdf,所以要下載下來然後在手機上看,當時的需求是要下載下來在App上檢視,經查詢,使用了第三方的外掛==》PDFView, PDFView基於G

Android仿支付寶扣款順序動態改變ListView各Item次序

前言:今天遇到個需求,需要讓使用者動態選擇語音傳輸方式的次序,突然想起支付寶選擇扣款順序的功能,恰好能滿足需要,就花了點時間寫了個demo,在此權當學習記錄 先上效果圖 支付寶的效果 demo的效果 思路: 用ListV

UITableViewCell 中的輸入框動態改變高度

根據輸入的內容,動態的改變高度,還是很好實現的。 按照一下的步驟,就可以了。 textViewDidChange { sizeThatFits //計算出需要多高 cellHeight = Height //設定成算出來的高度 self.tabl

通過Github Pages 自己的Html檔案釋出到伺服器可供遠端訪問

最近遇到了一個問題:將自己建立的、儲存在本地的Html檔案,上傳至伺服器,使他人能夠訪問。下面是總結的方法: 第一步,在github 中新建一個倉庫。 第二步,開啟setting,有一個Github P

如何本地檔案通過終端傳到linux伺服器 /伺服器/阿里雲

scp -P 埠 c://xxxx.txt [email protected]:/home/root 注意: -P 大寫 -i 公鑰 (我是將檔案上傳到阿里雲)   (1)在本地的終端下,而不是在伺服器上。在本地的終端上才能將本地的檔案拷入伺服器。 (2)

在Linux伺服器命令列下執行Matlab的.m檔案

1、採用shell工具例如xshell連線伺服器,鍵入 matlab ,或者含有matlab的相關命令,按照提示要求安裝Xmanager工具,只需官網下載,按說明安裝。 2、直接執行Matlab:$matlab,然後可以開啟matlab工具,根據xmanager工具可以在本地開啟matlab

如何一個 映象 pull到docker伺服器並且實現該image 處於 up狀態?

該文主要介紹:如何將映象pull到docker 伺服器上,並且實現該image處於up狀態? 這個相對來說是比較容易的、 1.搜尋需要pull的image [[email protected] ~]# docker search seleniu

如何一個伺服器的資料庫搞到另一個伺服器方法之一

以匯出資料的方式複製資料庫及資料。 首先在目標伺服器上建一個空資料庫,不用建表,最重要的是在選項裡面修改一下資料庫的排序規則,選擇Chinese_PRC_CI_AS,不然匯入資料後,中文將會變成亂碼。 1. 2. 3. 4.這裡選擇目標伺服器上剛建的空資料庫,這裡也可以新

thinkphp專案的資料庫的匯入以及thinkphp傳到伺服器

這幾天修改了一個thinkphp專案,並把它傳到伺服器上,說一下遇到的問題和收穫。 執行thinkphp專案安裝一個PHPstudy就可以執行,把專案檔案放到根目錄下。 然後就是連線資料庫,mysql資料庫可以用Navicat for MySQL這個執行,新建一個連線,在

Android 的res/values/colors自定義顏色列表和註釋表及佈局檔案常用顏色引用顏色設定

Android中設定文字顏色的四種方法: 一、利用系統自帶的顏色類 tx.setTextColor(android.graphics.Color.RED); 二、數字顏色表示 tx.setTextColor(0xffff00f); 三、自定義顏色 在

曹工雜談:Linux伺服器Spring Boot 原地修改 jar 包配置檔案/替換class檔案免去重複傳的麻煩

一、前言 相信很多同學有這樣的需求,現在很多公司都有多地的研發中心,經常需要跨地區部署,比如,博主人在成都,但是伺服器是北京的。一般城市間網路都不怎麼好,上傳一個幾十兆的jar包那是真的慢,別說現在微服務架構下,動輒兩位數的fat jar。這裡說的jar,就是spring boot專案打出來的fat jar

Android獲取本地檔案的真實路徑content型別轉為file型別

來源網路。記錄知識點以防備用..... 相容不同的機型獲取到的檔案路徑型別,以防異常情況發生。 public static String getPath(Context context, Uri uri) { if ("content".equalsIgnoreCase(uri.ge

Android smali檔案轉為jar包

想要將smali檔案轉成jar包,需要經過兩個步驟: 1.將smali檔案轉成dex檔案; 將smali轉dex我們需要用到smali.jar這個jar,然後在當前目錄輸入:java -jar smali.jar test/smali/ -o classes.dex 2.將dex檔案轉成

一.背景 先說下windbg使用場景.各位coder在工作中或多或少都會遇到下面四種情況 1.原生代碼好好的,伺服器執行一段時間後,IIS服務突然佔用 w3wp.exe CPU突然100% ,

一.背景 先說下windbg使用場景.各位coder在工作中或多或少都會遇到下面四種情況 1.原生代碼好好的,放伺服器上執行一段時間後,IIS服務突然佔用 w3wp.exe CPU突然100% ,不得不回收應用程式池,如果哪次回收晚了,被客戶發現,後果很痛苦~ 2.你的w3wp.

關於專案部署到伺服器介面資料正常狀態碼500可能是session報錯問題

剛開始一直報500錯誤,頁面不提示,也沒想著去檢視日誌檔案。好幾天了,一看日誌,發現是這個問題。問了一下,是session的問題、 2017/07/25 16:57:49 [error] 2300#0: *1 FastCGI sent in stderr: "PHP message: PHP Fatal e

網頁部署到伺服器

       當我們做了一寫漂亮的頁面時,可以將它部署到自己的伺服器上,方便用域名來進行訪問。             大三了,快要準備出去面試工作,於是做了一個

SpringMVC下圖片檔案伺服器

圖片檔案跨伺服器上傳(我使用的公司雲桌面作為上傳伺服器,自己的筆記本作為儲存伺服器測試的) 一、上傳伺服器: 1、pom檔案(使用jersey外掛) <!-- 上傳元件包 --> <dependency> <gro

Android cookie提交不到伺服器(解決方法)

在上篇具體問題已經說到,現在來說解決的辦法: 1.重新寫了一遍提交部分的程式碼, 2.去登入介面,查詢從伺服器獲取到的cookie,發現打包、以及包裝有問題,需要重新提交一份屬於該介面的cookiceStore; (因為我是接的別人的專案開始做的,所以前面有些不太瞭解,他的cookie方

Android 複製單個檔案到指定目錄Android copy file

package com.angding.util; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /**