某公司筆試題解讀(一)


  上午剛參加完一公司的筆試,整個筆試給我的感受是,比較基礎也很全面。但自己就是有好多不確定,好多需要時間思考,總之就是基礎需要補回來。下面我就總結一下這次的筆試,舉一反三地把相關知識點也梳理下。

一、最讓我抓狂的SQL題

  這種SQL題我以前做過好多次了,工作上SQL寫得不多,運用SQL的思維能力都下降了。題目大概是“有一張銷售營業額表(t_sales),表結構如下: 

CREATE TABLE t_sales(
    t_person VARCHAR(20),   #銷售人員
    t_item VARCHAR(100),    #商品
    t_sale INT,             #銷售額
    t_time DATE             #時間
)

  “求各種商品今年銷售額最高的銷售人員和商品名”

  這題目看它的數據結構應該是用Mysql寫的,我就用Mysql來解答吧(我當時用了oracle語法解答的,悲劇呀) 

SELECT t.* FROM 

    (SELECT t_item,t_person,SUM(t_sale) year_sale FROM t_sales 
        WHERE YEAR(t_time) = YEAR(NOW()) 
        GROUP BY t_item,t_person order by year_sale desc) t

    GROUP BY t.t_item 

 

-------2016.09.22更新---------------

其實上面就是用到了oracle的dense_rank() over(partition by order by)排序函數(非跳躍,兩個第一名的話,第三個就是第二名),上面的需求不太明確,下面我們就用學生每科成績來吧,找出每個科目成績最高分的學生和分數。

新建一張表並插入數據:

CREATE TABLE student (
       id INT(3), 
       name VARCHAR(20),
       subject VARCHAR(100),
       score INT(3));
       
INSERT INTO student VALUES (1, 'jack','語文', 90);
INSERT INTO student VALUES (2, 'tom','語文', 85);
INSERT INTO student VALUES (3, 'allen','語文', 95);#成績相同
INSERT INTO student VALUES (4, 'michael','語文', 95);#成績相同

INSERT INTO student VALUES (5, 'jack','數學', 93);
INSERT INTO student VALUES (6, 'tom','數學', 84);
INSERT INTO student VALUES (7, 'allen','數學', 89);
INSERT INTO student VALUES (8, 'michael','數學', 86);

mysql查詢的sql如下:

SET @rn=1;
SET @last_subject=NULL;#用來判斷是否在同一科目
SET @last_score=NULL;#用來判斷是否相同的分數

SELECT s.name AS "姓名",s.subject AS "科目",s.score AS "分數",s.rank "名次" from 
(SELECT 
    id,name,subject,score,

    #上一次查詢的科目等於本次查詢的,說明是同一個組,這實現了oracle的partition by
    #同組的還要判斷是否分數相同,如果相同還要有相同的名次
    IF(@last_subject = subject,IF(@last_score = score,@rn,@rn := @rn + 1),@rn := 1) AS rank,
    #把本條記錄的科目和分數賦值給變量
    @last_subject := subject as "last_subject",@last_score := score AS last_score
    FROM student
    #ORDER BY實際上實現了分組的功能
    ORDER BY subject,score DESC) s WHERE s.rank = 1

 

mysql查詢結果如下:

 

oracle就簡單了,sql如下:

SELECT s.name AS "姓名",s.subject AS "科目",s.score AS "分數",s.rank "名次" from 
       (SELECT t.*,DENSE_RANK() OVER(PARTITION BY subject ORDER BY score desc) rank FROM student t) s where s.rank = 1;

 

oracle運行結果:

 

二、cookie和session的代碼實現

 1、設置cookie

  今天筆試題考的是cookie的設置,我竟然選了request也可以設置cookie,我的天呀。

  我們來看如何在response設置吧

public void service(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
        
        Cookie c = new Cookie("name","jenkins");
        resp.addCookie(c);

 } 

  這樣子設置,實際上是在返回的消息頭中加了一個key-value,key為Set-Cookie,value也是key-value的形式,上面的就是:name=jenkins,多個cookie用分號(;)隔開

  消息頭中的樣式是:Set-Cookie:name=jenkins;JSESSIONID=ERERE23343423

  其實如果要在request中把cookie返回到服務器端,我們可以在請求的消息頭中加一個值:

package servletbase;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;

public class MyServlet01 extends HttpServlet{
    
    public void postCookieToServer(){
        HttpClient client = new HttpClient();
        List<Header> headers = new ArrayList<Header>();
        //把key為JSESSIONID的cookie上傳到服務器,服務器會根據這個id來判斷
        //發起該會話的用戶是不是之前登錄過,做鑒權
        headers.add(new Header("cookie","JSESSIONID=RERER3"));
     //設置消息頭
        client.getHostConfiguration().getParams().setParameter("http.default-headers", headers);
    }
    
}

2、查詢Cookie

  在請求對象中獲取:

public void getCookieFromRequest(HttpServletRequest request){
        //獲取cookie數組
        Cookie[] cookies = request.getCookies();
        for(Cookie cookie:cookies){
            //獲取cookie的key-value
            String name = cookie.getName();
            String value = cookie.getValue();
        }
    }

3、修改Cookie 

public void updateCookieFromRequest(HttpServletRequest request,HttpServletResponse response){
        //獲取cookie數組
        Cookie[] cookies = request.getCookies();
        for(Cookie cookie:cookies){
            //修改cookie的value
            String name = cookie.getName();
            if(name.equals("city")){
                cookie.setValue("guangzhou");
                response.addCookie(cookie);
            }
        }
    }

4、Cookie的編解碼(value為中文時需要編碼,否則訪問時會報錯)

     //編碼
        Cookie c = new Cookie("city",URLEncoder.encode("廣州","utf-8"));
        
        //解碼
        String value = c.getValue();
        value = URLDecoder.decode(value,"utf-8");

5、Cookie的其他方法

//設置生存時間,單位是秒,默認小於零,保存在內存中。等於零是即刻刪除
cookie.setMaxAge(30)

//設置路徑,瀏覽器訪問服務器時只向cookie路徑或者子路徑發送cookie,以下訪問/web/index.html是會發cookie,但訪問/myweb/index.html就不會了
cookie.setPath("/web");

 6、Cookie的限制

  a、可以被用戶限制

  b、保存在瀏覽器,不安全,敏感數據要進行加密

  c、只能保存少量數據,大約4k左右

  d、個數有限制

  e、只能保存字符串

7、Session定義和工作原理

  簡單來說Session就是服務器為每一個訪問的瀏覽器分配的內存空間,它有一個唯一的id,並且會將這個jsessionid以cookie的形式發送到瀏覽器(服務器調用了getSession()方法才會返回jsessionid到瀏覽器,並不是每個請求過來都返回),瀏覽器再次訪問時就會把這個jsessionid發送到服務器,服務器就能找到session對象。

  如果瀏覽器再次訪問(請求消息頭中帶有jessionid)時,服務器能找到對應的sessionid,則服務器不再返回sessionid到瀏覽器。

8、獲取Session 

//參數為true時一定會返回session對象
HttpSession session = request.getSession(true);
//不加參數默認是true
HttpSession session = request.getSession();

//參數為false時,則沒有sessionid時返回null
//有sessionid,但找不到session對象時也返回null,能找到session對象就返回該對象
HttpSession session = request.getSession(false);

9、使用Session綁定對象

//綁定對象
void session.setAttribute(String name,Object boj);
//獲取綁定對象
Object session.getAttribute(String name);
//移除綁定對象
void session.removeAttribute(String name);

//刪除session對象
session.invalidate();

10、Session超時

服務器會將空閑時間過長的session對象刪除以節省內存空間資源,一般是30分鍾 

在tomcat的conf/web.xml文件夾設置(單位是分鍾):

  <session-config>

    <session-timeout>30</session-timeout>

  </session-config>

通過編程修改:

  void session.setMaxInactiveInterval(int seconds)

11、瀏覽器禁用cookie后果及解決方法

  瀏覽器禁用cookie后,session就不能用了,因為jsessionid不能在瀏覽器保存。

  解決辦法:使用URL重寫方法解決,就是在重定向時在url中加sessionid參數,就不需要瀏覽器保存了。看以下的例子,假如登錄驗證過程了,需要重定向到首頁 

if(name.equals("admin") && pwd.equals("admin")){
            session.setAttribute("name",name);
            //重定向到首頁
            //response.sendRedirect("index.jsp");
             
            //改為,其會在路徑后面加上jsessionid,
            //System.out.println("url:" + resp.encodeRedirectURL("index.html")); --> url:index.html;jsessionid=4E885D5D87247441F761C96ACA9A7B68
            response.sendRedirect( response.encodeRedirectURL("index.jsp"));              
        }

  登錄之后我們就可以把sessionid保存到頁面,訪問時把它帶上就好了,可以在url后面加上sessionid,如下:

  localhost:8080/testweb/servlet01;jsessionid=4E885D5D87247441F761C96ACA9A7B68

  另外如果在服務器端沒有生成session對象,服務器是不會返回sessionid的cookie到瀏覽器的,即在服務器端要調用request.getSession()

12、Session的優缺點

  優點:

  a、安全(狀態保存在服務器端)

  b、能保存的數據類型更多,cookie只能是字符串

  c、能保存更多數據

  缺點:

  session將狀態保存在服務器端,占用服務器內存,當用戶量過大時,會嚴重影響服務器性能。

三、重定向與轉發的區別

  今天只考了代碼如何實現的,我就把他們原理和區b別總結一下吧

  1、重定向

  定義:服務器向瀏覽器發送一個302的狀態碼和一個Location消息頭(其值是一個地址),瀏覽器收到后會馬上向該地址發出請求。

  代碼實現:response.sendRedirect("/index.html");

  之后的代碼不能使用request和response,如下所示: 

response.sendRedirect("/index.html");
//response.sendRedirect("/login.html");  

  2、轉發

  定義:一個Web組件(Servlet/JSP)將未完成的處理通過容器轉交給另一個Web組件繼續完成。常見的是Servlet獲取數據之后將這些數據轉發給JSP,由這個JSP來負責展示

  代碼實現:request.getRequestDispatcher("index.jsp").forward(request,response);

    之后的代碼不能使用request和response,如下   

req.getRequestDispatcher("/servlet02").forward(req, resp);
//req.getRequestDispatcher("/servlet03").forward(req, resp);

  3、重定向與轉發的區別

  a、是否任意地址:重定向的地址可以任意地址,轉發必須是應用內的某一地址

  b、瀏覽器地址是否變:重定向瀏覽器地址欄會變,轉發瀏覽器地址欄不會變

  c、是否共享數據:重定向有兩次請求對象,不共享數據;轉發只生產一次請求對象,且在同一應用中共享數據。

  d、原理上的不同:重定向是瀏覽器收到響應后再向另外一個地址發出請求,轉發是收到請求為了完成響應轉到一個新地址。

四、request.getParameter()與request.getAttribute()的區別

  筆試考了他們返回的數據類型,request.getParameter()返回的是String,request.getAttribute()返回的是Object。下面看看他們的區別

1、HttpServletRequest類有setAttribute()方法,而沒有setParameter()方法

2、request.getParameter()負責獲取從瀏覽器或者其他HttpClient(get,post方式)上傳的參數。而request.getAttribute()是獲取容器內部轉發過來的數據,該數據需要用request.setAttribute()方法綁定,常見於Servlet中把獲取的數據轉發到JSP顯示。

參考:http://www.cnblogs.com/jirglt/archive/2012/10/25/2738617.html

五、javascript題

1、考變量賦值和返回

代碼如下,問執行后y的值是多少?

   var y = 0;
    function f(n){
        n += 1;
    }
    function m(){
        y = f(0);
    }

  結果是:undefined

  js的語法是比較弱的,沒有返回值的函數也能賦值到變量。

2、考js的日期函數

就是考Date對象的幾個函數,年月日 時分秒,我都總結一遍吧

     var now = new Date();
        var yy = now.getYear();//返回從1900開始算得年份間隔,2016就返回116
        yy = 1900 + yy;//加上1900就是2016了
        var MM = now.getMonth();//返回月份,范圍是0-11
        MM = MM + 1;//加上1就是正常月份
        var dd = now.getDate();//返回月份的第幾天,從1開始算

        var arr = new Array("星期日","星期一","星期二","星期三","星期四","星期五","星期六");
        var day = now.getDay();//返回星期,0是星期日,6是星期六
        var week = arr[day];

        var date = yy+"年"+MM+"月"+dd+"日"+"  "+week+"  ";

        var hh = now.getHours();//返回小時數,24小時制
        var mm = now.getMinutes();//返回分鍾數
        var ss = now.getTime();//返回日期的毫秒數
        ss = ss % 60000;//一分鍾取余數,單位是毫秒
        //ss % 1000是求得不夠一秒的毫秒數,與ss相減是為了求得能夠被1000整除的數
        ss = (ss - (ss % 1000)) / 1000;

        var time = hh + ":" + mm + ":" + ss;

        alert("現在的時間是:" + date + time);

 以上比較特殊的是年份、月份和星期

六、到處考的字符集編碼

  字符集編碼是特別困擾程序員的,我之前也有去研究過,但可能認識地不夠深入,筆試時也沒能答得很好。筆試是問“什么編碼是可以兼容gb2312的?”,我只選了GB18030,其實GBK也可以兼容的。

  網上找了些資料,再來梳理下這些麻煩的字符編碼集,就從他們的歷史順利開始吧

  1、ASCII(American Standard Code for Information Interchange,美國信息互換標准代碼)

    這應該是最早的編碼集,單字節,最多保存256個狀態(2的8次方),前127號已經用於英文、數、符號編碼,128以后的是擴展位

  2、ISO-8859-1

    單字節,兼容ASCII,用到了ASCII的擴展位,支持部分歐洲使用的語音。以ISO-8859-1編碼的文本,都以bytes[]的形式保存,若要顯示中文,則用中文編碼集解碼即可。如果用ISO-8859-1解碼則顯示亂碼。通常頁面上傳輸的編碼都是ISO-8859-1。

  3、gb2312

    1980年,一共收錄了7445個字符,包括6763個漢字和682個其它符號。很少用了。

  4、GBK

    是微軟對gb2312的擴展,是微軟標准但不是國際標准,向下兼容gb2312,出現於Windows 95簡體中文版中

  5、GB18030

    2000年,取代了GBK1.0的正式國家標准。該標准收錄了27484個漢字,同時還收錄了一些少數民族文字。編碼是一二四字節變長編碼。向下兼容gb2312,基本兼容gbk,單字節兼容ASCII

  6、Unicode(統一碼、萬國碼、單一碼)

    Unicode 是為了解決傳統的字符編碼方案的局限而產生的,它為每種語言中的每個字符設定了統一並且唯一的二進制編碼,以滿足跨語言、跨平台進行文本轉換、處理的要求。Unicode 16編碼里面已經包含了GB18030里面的所有漢字。總之它就是世界各國通用的字符編碼集,而不是每個國家自己搞一套,互不兼容。儲存每個字符都是用兩個字節,英文、漢字都是兩個字節,所以存儲英文比較浪費空間。

  上面講得都是字符集,我們在寫程序中經常用到的utf-8其實不是字符集,他只是一種編碼方式,是對字符集Unicode的再次編碼。utf-8是變長字符編碼,用1-4個字節表示一個字符,如用一個字節表示英文,中文占了3個字節。utf-8是為了解決網絡傳輸和存儲問題的,網絡上傳輸是8個位傳輸的,這滿足了寬帶傳輸的要求(utf-16就是16位傳輸);儲存時可以把英文單字節存儲節省空間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM