Quantcast
Channel: CSDN博客推荐文章
Viewing all 35570 articles
Browse latest View live

学前端,怎么能不会用Linux服务器部署?!

$
0
0

对读书学知识感兴趣的同学,欢迎关注公众号“精粹微阅读”(搜索微信号"jcwyd2016"或者直接搜索公众号名字),和读书有关的,更新经济、政治、运动、法律、设计、沟通、管理等等各个方面的书籍知识总结~感兴趣的同学欢迎来看一下哟~


最近尝试了一下使用“腾讯云”的服务器(有云+校园计划,一个月只要一块钱就可以啦)。

最后购买了一个Linux的服务器。购买好腾讯云服务器,就开始了第一次在Linux上自己部署nodejs应用了。下面


一、开启服务器

购买服务器时,推荐大家一定要买Linux服务器,毕竟现在大多数都是用Linux服务器部署项目的。选择CentOS的最新版本即可。

购买成功之后,进入腾讯云服务器的后台管理界面,登陆服务器。首先输入用户名root,然后输入自己在购买时设定的密码,就可以成功登陆了。


二、在Linux上配置node环境

要想在Linux上配置node环境,需要使用源代码安装的方式。进入nodejs官网下载页面,有用于Linux的源码安装包(Source Code),如下:


这里有两种方法将这个源码文件拷贝到Linux服务器中。一种是在本地下载压缩包,然后上传到远程服务器;另一种是直接在Linux服务器上执行下载命令。这里选用后一种方法,这种方法更简便。执行如下命令:

wget https://nodejs.org/dist/v6.10.0/node-v6.10.0.tar.gz

后面的url,对应的就是下载文件的url,该文件会被下载到当前目录下。

这是一个压缩文件,需要进行解压操作,执行如下命令:

tar xvf node-v6.10.0.tar.gz

就可以完成解压了。

注意,由于node是使用C++实现的,因此要想通过解析源码配置node环境,首先需要在Linux服务器下配置C和C++的环境,这里使用yum安装,执行如下代码:

sudo yum install gcc gcc-c++

配置好C环境后,就可以进行node安装了,进入到node-v*目录后,依次执行如下命令:

./configure

make

这需要一段时间,不要心急。命令都执行成功后,再执行

sudo make install

最后就完成安装了,这样安装成功后,还会自动安装好npm环境。


三、使用SCP上传文件到远程Linux服务器

在本地开发好的项目,可以直接上传的远程Linux服务器中进行部署,方法很简单,例如在本地的终端中执行下面这行命令:

scp  -r /opt/test root@192.168.12.115:/opt

这段代码就表示,将本地的/opt/test文件,上传到对应远程Linux服务器中的/opt文件下。



什么都懂一点,生活才多彩些。这是一个带你读书学知识的公众号~


作者:fareise 发表于2017/3/25 16:53:57 原文链接
阅读:276 评论:0 查看评论

hostapd wpa_supplicant madwifi详细分析(十五)——supplicant扫描结果排序规则

$
0
0
int (*compar)(const void *, const void *) = wpa_scan_result_compar;

qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),compar);  // qsort函数介绍

static int wpa_scan_result_compar(const void *a, const void *b)  //这个函数用于scan result结果降序排序
{
#define MIN(a,b) a < b ? a : b
    struct wpa_scan_res **_wa = (void *) a;  //scan result的二级指针
    struct wpa_scan_res **_wb = (void *) b;
    struct wpa_scan_res *wa = *_wa; //scan result的一级指针
    struct wpa_scan_res *wb = *_wb;
    int wpa_a, wpa_b;
    int snr_a, snr_b, snr_a_full, snr_b_full;

    /* WPA/WPA2 support preferred */
    wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
        wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
    wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
        wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;

    if (wpa_b && !wpa_a) //这里先比较是否有WPA_IE_VENDOR_TYPE和WLAN_EID_RSN这两个IE,谁有就谁排在前面,如果都没有,就不将他们看作排序因子
        return 1;  //返回正数表示升序,反会负表示逆序,返回0表示相等,所以正数时表示a比b小,负数时表示a比b大
    if (!wpa_b && wpa_a)
        return -1; //这里返回负数,表示将a放在b的后面

    /* privacy support preferred */
    if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&  //如果有标志位IEEE80211_CAP_PRIVACY的,就排在前面
        (wb->caps & IEEE80211_CAP_PRIVACY))
        return 1;
    if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
        (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
        return -1;

    if (wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) {
        snr_a_full = wa->snr;
        snr_a = MIN(wa->snr, GREAT_SNR); //如果信噪比大于30,那么信噪比snr_a的值就赋值为30,所以当wa->snr大于30的时候,snr_a_full是真实值,snr_a是阈值
        snr_b_full = wb->snr;
        snr_b = MIN(wb->snr, GREAT_SNR); //通过log可知,其实排序的时候没有用到信噪比这个因子
    } else {
        /* Level is not in dBm, so we can't calculate
         * SNR. Just use raw level (units unknown). */
        snr_a = snr_a_full = wa->level;   //level表示信号强度,一般用百分比表示,和信噪比的算法不一样
        snr_b = snr_b_full = wb->level;
    }

    /* if SNR is close, decide by max rate or frequency band */
    if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||     //如果两者的level相差在5以内,就认为两者是相等的
        (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {  //如果两者的信号质量相差在10以内,就认为两者是相等的
        if (wa->est_throughput != wb->est_throughput)  //Enrollment over Secure Transport, 我们没有用这种协议,所以两者都是0, 非排序因子
            return wb->est_throughput - wa->est_throughput;
        if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))   //如果两者都是5G,那就不用比较了,如果其中一个是5G,另外一个不是,那么5G的排在前面
            return IS_5GHZ(wa->freq) ? -1 : 1;
    }

    /* all things being equal, use SNR; if SNRs are
     * identical, use quality values since some drivers may only report
     * that value and leave the signal level zero */
    if (snr_b_full == snr_a_full)   //如果运行到这里还没有return,就表示前面的那些参数都是相等的,所以这里看看两者的真是信噪比是否相等
        return wb->qual - wa->qual; //如果相等,那就比信号质量,信号质量高的排在前面
    return snr_b_full - snr_a_full; //如果不相等,那就比真实信噪比,信噪比高的排在前面
#undef MIN
}



作者:lee244868149 发表于2017/3/25 18:15:59 原文链接
阅读:90 评论:0 查看评论

Openlayers中Google地图的加载

$
0
0

概述:

本文讲述如何在Openlayers中加载Google的切片。


效果:


矢量图


影像图

实现:

在实现的时候,参考了mygisforum的文章http://blog.csdn.net/mygisforum/article/details/7582449的内容,同时结合gwc的gridset,实现了google切片在Openlayers2中的调用与展示。


1、扩展的GoogleLayer代码如下:

OpenLayers.Layer.GoogleLayer = OpenLayers.Class(OpenLayers.Layer.XYZ, {
    url: null,
    tileOrigin: null,
    tileSize: new OpenLayers.Size(256, 256),
    type: 'png',
    useScales: false,
    overrideDPI: false,
    initialize: function(name, url, options) {
    	this.lyrs = options.lyrs;
        OpenLayers.Layer.XYZ.prototype.initialize.apply(this, arguments);
    },
    getURL: function (bounds) {
        var res = this.getResolution();
        var originTileX = (this.tileOrigin.lon + (res * this.tileSize.w/2));
        var originTileY = (this.tileOrigin.lat - (res * this.tileSize.h/2));
        var center = bounds.getCenterLonLat();
        var x = (Math.round(Math.abs((center.lon - originTileX) / (res * this.tileSize.w))));
        var y = (Math.round(Math.abs((originTileY - center.lat) / (res * this.tileSize.h)))); 
        var z = this.map.getZoom();
        var url = this.url;
        var s = '' + x + y + z;
        if (OpenLayers.Util.isArray(url)) {
            url = this.selectUrl(s, url);
        }
        url = url + '?lyrs=${lyrs}&hl=zh-CN&gl=CN&z=${z}&x=${x}&y=${y}';//&L=4&X=12&Y=3
        url = OpenLayers.String.format(url, {'lyrs': this.lyrs, 'x': x, 'y': y, 'z': z});
        return OpenLayers.Util.urlAppend(
            url, OpenLayers.Util.getParameterString(this.params)
        );
    },

    CLASS_NAME: 'OpenLayers.Layer.GoogleLayer'
}); 

2、前台调用展示代码如下:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>openlayers map</title>
    <link rel="stylesheet" href="../../../plugin/OpenLayers-2.13.1/theme/default/style.css" type="text/css">
    <style>
        html, body,#map{
            padding:0;
            margin:0;
            height:100%;
            width: 100%;
            overflow: hidden;
        }
    </style>
    <script src="../../../plugin/OpenLayers-2.13.1/OpenLayers.js"></script>
    <script src="../../../plugin/jquery/jquery-1.8.3.js"></script>
    <script src="extend/GoogleLayer.js"></script>
    <script>
        var map;
        $(window).load(function() {
            var bounds = new OpenLayers.Bounds(
                5107331.309416,3478249.787475,17865588.574552,5689420.141709
            );
            var mapOptions = { 
				resolutions: [156543.03390625, 78271.516953125, 39135.7584765625, 19567.87923828125, 9783.939619140625, 4891.9698095703125, 2445.9849047851562, 1222.9924523925781, 611.4962261962891, 305.74811309814453, 152.87405654907226, 76.43702827453613, 38.218514137268066, 19.109257068634033, 9.554628534317017, 4.777314267158508, 2.388657133579254, 1.194328566789627, 0.5971642833948135, 0.29858214169740677, 0.14929107084870338, 0.07464553542435169, 0.037322767712175846, 0.018661383856087923, 0.009330691928043961, 0.004665345964021981, 0.0023326729820109904, 0.0011663364910054952, 5.831682455027476E-4, 2.915841227513738E-4, 1.457920613756869E-4],
				projection: new OpenLayers.Projection('EPSG:900913'),
				maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
				units: "meters",
				controls: [
					new OpenLayers.Control.Zoom(),
					new OpenLayers.Control.Navigation(),
					new OpenLayers.Control.LayerSwitcher()
				]
			};
            map = new OpenLayers.Map('map',mapOptions);
            /*
             * m@177000000,矢量
             * s@110,影像
             */
            var googleUrl = "http://mt1.google.cn/maps/vt";
            var vectorLyr = new OpenLayers.Layer.GoogleLayer( "VectorLayer",
                    googleUrl, 
                    {
                        lyrs:"m@177000000",
                        isBaseLayer: true,
                        resolutions: mapOptions.resolutions,
                        tileOrigin: new OpenLayers.LonLat(-20037508.34,20037508.34 ),
                        maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
                        projection: 'EPSG:900913'
                    });
                var imageLyr = new OpenLayers.Layer.GoogleLayer( "ImageLayer",
                    googleUrl, 
                    {
                    	lyrs:"s@110",
                        isBaseLayer: true,
                        resolutions: mapOptions.resolutions,
                        tileOrigin: new OpenLayers.LonLat(-20037508.34,20037508.34 ),
                        maxExtent: new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34),
                        projection: 'EPSG:900913'
                    });
              var wms1 = new OpenLayers.Layer.WMS("base_map",
					"http://localhost:8088/geoserver/lzugis/wms",
					{
						layers: "capitalweb",
						transparent: true
					}, {
						isBaseLayer: false,
						singleTile: true//是否切片加载,false是,true不是
					});
            map.addLayers([vectorLyr,imageLyr, wms1]);
            map.zoomToExtent(bounds);
        });
    </script>
</head>
<body>
<div id="map" style="width: 100%;"></div>
</body>
</html>`


说明:

1、因为在国内,所以无法调用google map域名的切片,所以选用google.cn域名下的切片数据;

2、在参数lyrs中, m@177000000代表矢量切片,s@110代表影像切片

---------------------------------------------------------------------------------------------------------------

技术博客

CSDN:http://blog.csdn.NET/gisshixisheng

博客园:http://www.cnblogs.com/lzugis/

在线教程

http://edu.csdn.Net/course/detail/799

Github

https://github.com/lzugis/

联系方式

q       q:1004740957

e-mail:niujp08@qq.com

公众号:lzugis15

Q Q 群:452117357(webgis)

             337469080(Android)

作者:GISShiXiSheng 发表于2017/3/25 18:39:08 原文链接
阅读:111 评论:0 查看评论

Java for Web学习笔记(四六):WebSocket(3)Java Server

$
0
0

Maven相关库

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>

注意,这里是provided,不是compiled,已经集成在JavaEE 7中。上面是支持WebSocket Server和Client的,如果我们只需要Client,可以使用:

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-client-api</artifactId>
    <version>1.1</version>
    <scope>provided</scope>
</dependency>

一个简单的WebSocket Server

承接之前WebSocket Client的小例子,server在收到WebSocket请求后发出Hello消息,然后采用异步方式,每隔1秒发送一个消息,连发三次,然后关闭连接。

//【1】进行websocket server endpoint的标注,给出匹配的url。当收到一个webSocket请求时,会创建一个实例,这点和Servlet不一样,需要注意。
@ServerEndpoint("/test/{id}")
public class TestServer {
    //【2】server和client握手后,同样提供了@OnOpen, @OnClose, @OnError和@OnMessage触发发放,这些方法可以通过@PathParam()来获取path的信息,如本例中的id。我们可以通过javax.websocket.Session来发送信息和关闭连接

    //【2.1】可选的Session参数,可选的EndpointConfig参数,以及path信息
    @OnOpen
    public void onOpen(Session session, @PathParam("id") String id){
        System.out.println("onOpen : (" + id + ")");
        try {
            session.getBasicRemote().sendText("Hello, " + id);

            new Thread(new Runnable() {
                public void run() {
                    for(int i = 0 ; i < 3 ; i ++){
                        try {
                            Thread.sleep(1000);
                            session.getBasicRemote().sendText("count " + i);
                        } catch (Exception e) {
                        }                        
                    }
                   try {
                       session.close();
                   } catch (IOException ignoreE) {
                   }
               }
            }).start();
        } catch (IOException e) {
            e.printStackTrace();
        }        
    }

    //【2.2】消息的参数会比较复杂
    //    1、String给出text消息,如本例
    //    2、String以及boolean表示chunks,true表示为最后一个chunks。
    //    3、One Java primitive or primitive wrapper to receive an entire text message converted to that type
    //    4、One java.io.Reader to receive a text message as a blocking stream
    //    5、One byte[] or one java.nio.ByteBuffer to receive an entire binary message
    //    6、One byte[] or one ByteBuffer, plus one boolean to receive a binary message in chunks
    //    7、One java.io.InputStream to receive a binary message as a blocking stream
    //    8、One PongMessage for custom handling of heartbeat responses
    //    9、Any Java object if the endpoint has a Decoder.Text, Decoder.Binary, Decoder .TextStream, or Decoder.BinaryStream registered to convert that type. The message type of text or binary must match the registered decoder.
    @OnMessage
    public void onMessage(Session session, String message, @PathParam("id") String id){
        System.out.println("onMessage : (" + id + ") " + message);
    }

    //【2.3】可选的Session参数,可选的CloseReason参数,以及path信息
    @OnClose
    public void onClose(Session session, @PathParam("id") String id){
        System.out.println("onClose : (" + id + ")");
    }

    //【2.4】@OnError提供可选的Session参数,必选的Throwable,以及path信息,本例无处理
}

更为复杂一点的处理


两个client之间的通信

server可以作为agent之类的,实现两个或者多个client之间的通信,方式很简单,将session关联即可。

@ServerEndpoint("/ticTacToe/{gameId}/{username}")
public class GameServer {
    private static class Game{
        public long gameId;
        public Session player1;
        public Session player2;
        public TicTacToeGame ticTacToeGame;    
    }

    //我们通过gameId可以获得两个关联的client的session。
    private static Map<Long, Game> games = new Hashtable<>();

    ... 略 ...
}

使用JSON作为Message

Gson是一个选择,我们也可以使用可能更为传统的方式:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.8.7</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.8.7</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.8.7</version>
        <scope>compile</scope>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.8.7</version>
        <scope>compile</scope>
    </dependency>
@ServerEndpoint("/ticTacToe/{gameId}/{username}")
public class GameServer {
    ... 见上面代码片段,略 ...

    //(1)消息的基础格式
    public static abstract class Message{
        private final String action;
        public Message(String action){
            this.action = action;
        }
        public String getAction() {
            return action;
        }        
    }

    //(2)具体的消息类型
    public static class GameStartedMessage extends Message{
        private final TicTacToeGame game;

        public GameStartedMessage(TicTacToeGame game) {
            super("gameStarted");
            this.game = game;
        }

        public TicTacToeGame getGame() {
            return game;
        }        
    }

    ... 其他的消息类型,略 ...
    //【1】定义json封装
    private static ObjectMapper mapper = new ObjectMapper();

    //【2】发送JSON消息
    private void sendJsonMessage(Session session, Game game, Message message){
        try {
            session.getBasicRemote().sendText(GameServer.mapper.writeValueAsString(message));
        } catch (Exception e) {
            handleException(e,game);
        } 
    }

    //【3】解析JSON消息
    @OnMessage
    public void onMessage(Session session, String message, @PathParam("gameId") long gameId){
        Game game = GameServer.games.get(gameId);
        ... ...
        //解析JSON
        MoveMessage move = GameServer.mapper.readValue(message, MoveMessage.class);
        ... ...
        //发送JSON
        this.sendJsonMessage((isPlayer1 ? game.player2 : game.player1), game,
                    new OpponentMadeMoveMessage(move));
    }
}

从session中获取信息

在jsp文件中,我们用javascript写到

server = new WebSocket('ws://' + window.location.host +
                            '<c:url value="/game/${gameId}/${username}">'
                            +'<c:param name="action" value="${action}" />'
                            +'</c:url>');

我们要读出握手的HTTP请求的相关信息,例如action参数的值

//在WebSocket server中,如果我们需要获取action的信息
//getRequestParameterMap:Return the request parameters associated with the request this session was opened under.
List<String> actions = session.getRequestParameterMap().get("action");
if(actions != null && actions.size() == 1){
    String action = actions.get(0);
    ... ...
}

相关链接: 我的Professional Java for Web Applications相关文章

作者:flowingflying 发表于2017/3/25 18:49:20 原文链接
阅读:77 评论:0 查看评论

Java for Web学习笔记(四七):WebSocket(4)Java Client和二进制消息

$
0
0

小例子说明

不是所有的Client都是前端页面,服务器也可能发起一个WebSocket连接,向其他服务器请求某项服务。小例子模拟两个WebSocket客户端,向server建立连接,当server收到消息时,向所有的连接的client分发该消息,当某个client连接或者关闭连接时,向其他client发布状态变化消息。

为了方便测试,client和server都在同一个web app中,要求client启动连接和发送消息,使用servlet进行触发。

二进制的消息

二进制消息需要进行序列化。在Java中对象序列化比JSON要高效,但是与非Java的程序互动,流行JSON。

public class ClusterMessage implements Serializable{
    private static final long serialVersionUID = 1L;

    private String nodeId;
    private String message;

    public ClusterMessage(){        
    }

    public ClusterMessage(String nodeId , String message){
        this.nodeId = nodeId;
        this.message = message;
    }

    public String getNodeId() {
        return nodeId;
    }

    public void setNodeId(String nodeId) {
        this.nodeId = nodeId;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }        
}

Cluster Server代码

我们重点学习如何解析二进制消息,如何发送二进制消息。

@ServerEndpoint("/clusterNodeSocket/{nodeId}")
public class ClusterNodeServerEndpoint {
    //存储所有的client,以便进行消息广播
    private static final List<Session> nodes = new ArrayList<>(2);

    @OnOpen
    public void onOpen(Session session, @PathParam("nodeId") String nodeId){
        System.out.println("Node [" + nodeId  + "] connected to cluster server");
        ClusterMessage message = new ClusterMessage(nodeId, "Joined the cluster.");
        try {
            byte[] bytes = ClusterNodeServerEndpoint.toByteArray(message);
            for(Session node : nodes){
                node.getBasicRemote().sendBinary(ByteBuffer.wrap(bytes));
            }
        } catch (IOException e) {
            System.out.println("Exception when notifying of new node : " + e.toString());
            e.printStackTrace();
        }
        ClusterNodeServerEndpoint.nodes.add(session);
    }

    @OnMessage
    public void onMessage(Session session, byte[] message){
        try{
            for(Session node : ClusterNodeServerEndpoint.nodes){
                if(node != session)
                    node.getBasicRemote().sendBinary(ByteBuffer.wrap(message)); //发送二进制消息byte[]
            }
        }catch (IOException e) {
            logger.error("Exception when handling message on server : " + e.toString());
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(Session session, @PathParam("nodeId") String nodeId){
        System.out.println("Node [" + nodeId + "] disconnected.");
        ClusterNodeServerEndpoint.nodes.remove(session);
        ClusterMessage message = new ClusterMessage(nodeId, "Left the cluster.");
        try{
            for(Session node : ClusterNodeServerEndpoint.nodes){
                node.getBasicRemote().sendBinary(ByteBuffer.wrap(
                                                    ClusterNodeServerEndpoint.toByteArray(message)));
            }
        }catch (IOException e) {
            System.out.println("Exception when notifying of left node : " + e.toString());
            e.printStackTrace();
        }        
    }

    //将对象转换为byte[]: message(ClusterMessage) -> stream(ObjectOutputStream) --> output(ByteArrayOutputStream)
    private static byte[] toByteArray(ClusterMessage message) throws IOException {
        try(ByteArrayOutputStream output = new ByteArrayOutputStream();
            ObjectOutputStream stream = new ObjectOutputStream(output)){
               stream.writeObject(message);
                return output.toByteArray();
        }
    }
}

Cluster Client代码

我们模拟两个webSocket clients,为了方便触发,采用Servlet。在web.xml中定义如下,将两个servlet指向同一个类

   <servlet>
       <servlet-name>clusterNode1</servlet-name>
       <servlet-class>cn.wei.flowingflying.chapter10.cluster.ClusterNodeServlet</servlet-class>
       <init-param>
           <param-name>nodeId</param-name>
           <param-value>1</param-value>
       </init-param>
   </servlet>
   <servlet-mapping>
       <servlet-name>clusterNode2</servlet-name>
       <url-pattern>/clusterNode2</url-pattern>
   </servlet-mapping>

   <servlet>
       <servlet-name>clusterNode2</servlet-name>
       <servlet-class>cn.wei.flowingflying.chapter10.cluster.ClusterNodeServlet</servlet-class>
       <init-param>
           <param-name>nodeId</param-name>
           <param-value>2</param-value>
       </init-param>
   </servlet>
   <servlet-mapping>
       <servlet-name>clusterNode2</servlet-name>
       <url-pattern>/clusterNode2</url-pattern>
   </servlet-mapping>

WebSocket代码如下:

//annotation @ClientEndpoint 不会像@ServiceEndpoint 那样自动实例化,只是作为一个有效endpoint的标记
@ClientEndpoint
public class ClusterNodeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    private String nodeId;
    private Session session;

    //在init()时读取配置信息,建立webSocket连接
    @Override
    public void init() throws ServletException {
        this.nodeId = this.getInitParameter("nodeId");
        String path = this.getServletContext().getContextPath() +
                      "/clusterNodeSocket/" + this.nodeId;
        try {
            //【1】连接webSocket server
            URI uri = new URI("ws","localhost:8080",path,null,null);        
            this.session = ContainerProvider.getWebSocketContainer().connectToServer(this, uri);        
        } catch (URISyntaxException  | DeploymentException | IOException e) {
            e.printStackTrace();
            throw new ServletException("Cannot connect to " + path + ".", e);
        }
    }

    @Override
    public void destroy() {
        try {
            this.session.close(); //关闭webSocket连接
        } catch (IOException e) {
            e.printStackTrace();
        }
        super.destroy();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //【2】发送对象的二进制消息
        ClusterMessage message = new ClusterMessage(this.nodeId,
                  "request:{ip:\"" + request.getRemoteAddr() + "\",queryString:\"" + request.getQueryString() + "\"}");
        try(OutputStream output = this.session.getBasicRemote().getSendStream();
            ObjectOutputStream stream = new ObjectOutputStream(output)){
            stream.writeObject(message);
        }
        response.getWriter().append("OK");
    }

    @OnMessage
    public void onMessage(InputStream input){
        //【3】读二进制信息
        try(ObjectInputStream stream = new ObjectInputStream(input)){
            ClusterMessage message = (ClusterMessage)stream.readObject();
            System.out.println("Node [" + this.nodeId + "]: Message received from cluster; node = " +
                               message.getNodeId() + ", message = " + message.getMessage());
        }catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        } 
    }

    @OnClose
    public void onClose(CloseReason reason){
        CloseReason.CloseCode code = reason.getCloseCode();
        if(code != CloseReason.CloseCodes.NORMAL_CLOSURE){
            System.out.println("WebSocket connection closed unexpectedly;" +
                               " code = " + code + ", reason = " + reason.getReasonPhrase());
        }
    }
}

相关链接: 我的Professional Java for Web Applications相关文章
作者:flowingflying 发表于2017/3/25 20:28:53 原文链接
阅读:199 评论:0 查看评论

最长公共连续子串

$
0
0

牛牛有两个字符串(可能包含空格),牛牛想找出其中最长的公共连续子串,希望你能帮助他,并输出其长度。
输入描述:
输入为两行字符串(可能包含空格),长度均小于等于50.

输出描述:
输出为一个整数,表示最长公共连续子串的长度。

输入例子:
abcde
abgde

输出例子:
2


PS:这道题不得不说真的很坑,先不说空格也算成字符,连最长公共连续子串这个概念也和刷传统相关题用的概念也一样。


代码如下:

import java.util.Scanner;

/**
 * @author Administrator
 *
 */
public class Main {
    static String str1;
    static String str2;
    static int[][] dp;
    static int Max;

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        str1 = in.nextLine();
        str2 = in.nextLine();
        int len1 = str1.length();
        int len2 = str2.length();
        if ( len1 < 1 || len2 < 1){
            System.out.print(0);
        }

        dp = new int[str1.length()+1][str2.length()+1];
        char[] ch1 = str1.toCharArray();
        char[] ch2 = str2.toCharArray();

        for ( int i = 0 ; i < len1 ; i++){
            if ( ch1[i] == ch2[0]){
                dp[i][0] = 1;
            }
        }

        for ( int i = 0 ; i < len2 ; i++){
            if ( ch2[i] == ch1[0]){
                dp[0][i] = 1;
            }
        }

        Max = dp[0][0];
        for ( int i = 1 ; i < len1 ; i++){
            for ( int j = 1 ; j < len2 ; j++){
                if ( ch1[i] == ch2[j]){
                    dp[i][j] = dp[i-1][j-1]+1;
                }
                if ( dp[i][j] > Max){
                    Max = dp[i][j];
                }
            }
        }


        System.out.print(Max);
        in.close();
    }
}
作者:qq_30091945 发表于2017/3/25 20:33:56 原文链接
阅读:153 评论:0 查看评论

Java for Web学习笔记(四八):WebSocket(5)encoder,decoder和configurator

$
0
0

模拟聊天的例子

在Professional Java for Web Applications中给通书的例子中给出如何利用WebSocket实现聊天室的例子,作为案例,学习一下。用户可以进入聊天室聊天,HTTPSession终结,WebSocket也相应关闭。因此小例子中Server Endpoint是承载在一个HttpSessionListener之上。

在sessionDestroyed()中,关闭WebScoket,向聊天的对方提示状态。

Endpoint的annotation

我们先看看@ServerEndpoint和@ClientEndpoint的例子

@ServerEndpoint(
   value = "/sample",
   decoders = ChatDecoder.class,
   encoders = DisconnectResponseEncoder.class,
   subprotocols = {"subprtotocol1", "subprotocol2"},
   configurator = Configurator.class )

@ClientEndpoint(
   decoders = SampleDecoder.class,
   encoders = SampleEncoder.class,
   subprotocols = {"subprtotocol1", "subprotocol2"},
   configurator = ClientConfigurator.class)

subprotocols就是握手过程中HTTP header Sec-WebSocket-Protocol。网上有很个很好的教程 https://tyrus.java.net/documentation/1.4/index/websocket-api.html

configurator

//我们重点学习这种写法:在@ServerEndpoint或@ClientEndpoint中
// (1)指定消息的编码器和解码器,可以在onMessage接口中直接获得对象,通过RemoteEndpoint.Basic|Async.sendObject()发送对象
// (2)设定configurator,通过对ServerEndpointConfig.Configurator的继承,可以将一些request的属性或参数,放入WebSocket.Session中
@ServerEndpoint(value = "/chat/{sessionId}",
    encoders = ChatMessageCodec.class,
    decoders = ChatMessageCodec.class,
    configurator = ChatEndpoint.EndpointConfigurator.class)
@WebListener
public class ChatEndpoint implements HttpSessionListener {
    private static final String HTTP_SESSION_PROPERTY = "cn.wei.flowingflying.chat.HTTP_SESSION";
    ... ...
    @OnOpen
    public void onOpen(Session session, @PathParam("sessionId") long sessionId){
        //【2】获取通过configurator存放在Session中的属性
        HttpSession httpSession = (HttpSession)session.getUserProperties().get(ChatEndpoint.HTTP_SESSION_PROPERTY);
        ... ...
    }

    @OnMessage
    public void onMessage(Session session, ChatMessage message) {
        ... ...
    }

    @OnClose
    public void onClose(Session session, CloseReason reason){
        ... ...
    }

    @OnError
    public void onError(Session session, Throwable e){
        ... ...
    }
    
   /**
    * @see HttpSessionListener#sessionCreated(HttpSessionEvent)
    */
   public void sessionCreated(HttpSessionEvent se)  { /* do nothing */   }

   /**
    * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
    */
    public void sessionDestroyed(HttpSessionEvent event)  { 
        ... ...
    }

    //【1】设定configurator:本例子将HttpSession放入Session的属性中。modifyHandshake也就是握手阶段HTTP交换。
    public static class EndpointConfigurator extends ServerEndpointConfig.Configurator{
        @Override
        public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
            super.modifyHandshake(config, request, response);
            config.getUserProperties().put(ChatEndpoint.HTTP_SESSION_PROPERTY, request.getHttpSession());
        }
    } 
}

encoder和decoder

例子中消息ChatMessage将采用JSON的格式进行传递。下面演示了一个含有enum类型的处理:

public class ChatMessage {
    private OffsetDateTime timestamp;
    private Type type;
    private String user;
    private String content;

    ... 作为一个POJO的getters 和 setters,略...    

    public static enum Type {
        STARTED, JOINED, ERROR, LEFT, TEXT
    }
}

下面是一个消息的例子

{"user":"wei","content":"Hello, world!","timestamp":1490235820.560000000,"type":"JOINED"}

Encoder和decoder虽然有文本和二进制两种方式,本例子采用二进制方式,虽然JSON常使用String格式。对于String的方式,可以参考Websockets: using Encoders and Decoders

//实现Encode.BinaryStream和Decoder.BinaryStream,其他格式还有 Encode.Binary/Decoder.Binary,Encoder.Text/Decoder.Text 或者 Encoder.TextStream/Decoder.TextStream
public class ChatMessageCodec implements Encoder.BinaryStream<ChatMessage>,Decoder.BinaryStream<ChatMessage>{
    //【1】定义JSON的Mapper及其相关属性
    private static final ObjectMapper MAPPER = new ObjectMapper();
    static {
        MAPPER.findAndRegisterModules();
        MAPPER.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false);
    }

    @Override
    public void init(EndpointConfig config) {     }

    @Override
    public void destroy() {    }

    //【2】实现decoder
    @Override
    public ChatMessage decode(InputStream inputStream) throws DecodeException, IOException {
        try{
            return ChatMessageCodec.MAPPER.readValue(inputStream, ChatMessage.class);
        }catch(JsonGenerationException | JsonMappingException e){
            throw new DecodeException((ByteBuffer)null, e.getMessage(), e);
        }
    }

    //【3】实现encoder 
    @Override
    public void encode(ChatMessage chatMessage, OutputStream outputStream) throws EncodeException, IOException {
        try{
            ChatMessageCodec.MAPPER.writeValue(outputStream, chatMessage);
        }catch(JsonGenerationException | JsonMappingException e){
            throw new EncodeException(chatMessage, e.getMessage(), e);
        }
    }
}

Client:发送JSON的二进制消息

下面是相关的JavaScript:

 send = function() {
     if(server == null) {
         ... ...
     } else {
         var message = {
             timestamp: new Date(), type: 'TEXT', user: username,
             content: messageArea.get(0).value
         };
         try {
             var json = JSON.stringify(message);
             var length = json.length;
             var buffer = new ArrayBuffer(length);
             var array = new Uint8Array(buffer);
             for(var i = 0; i < length; i++) {
                 array[i] = json.charCodeAt(i);
             }
             server.send(buffer);
             messageArea.get(0).value = '';
        } catch(error) {
             modalErrorBody.text(error);
             modalError.modal('show');
        }
    }
};

相关链接: 我的Professional Java for Web Applications相关文章

作者:flowingflying 发表于2017/3/25 20:36:38 原文链接
阅读:87 评论:0 查看评论

通讯录第四版

$
0
0

最近在看mysql,想起以前写过通讯录,所以就想着将通讯录中的内容存储到mysql中

注意:下面出现的book是我的数据库中一张表的名字,它的字段是(name,tel,mail,addr)。根据情况自己替换
这里写图片描述

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<mysql.h>

#define SIZE 1024
MYSQL mysql;   //mysql的句柄
void Connect(const char* host,const char* user,const char* passwd,const char* db)  //进行数据库的连接
{
    mysql_init(&mysql);  //初始化mysql句柄

    if(!mysql_real_connect(&mysql,host,user,passwd,db,3306,NULL,0))    
    {
        printf("mysql_real_connect faile\n");
        exit(1);
    }
    printf("mysql connect success\n");
}

//name tel  mail addr    通讯录的结构
void Insert(const char* msg)    //向数据库里面进行插入一条信息
{
    //插入的SQL语句:insert into 表名 (列名1,列名2,列名3,列名4) values (name,tel,mail,addr)
    //或使用load data local infile '文本名' into table 表名 批量插入到数据库中
    if(msg)
    {
        char buf[SIZE]="insert into book (name,tel,mail,addr) values ";
        strcat(buf,msg);
        int len=strlen(buf);
        if(mysql_real_query(&mysql,buf,len))    //mysql_real_query失败返回非0
        {
            printf("mysql_real_query insert faile\n");
            return;
        }
    }
}

void Delete(const char* condition)    //删除数据库里面的某一条信息
{
    //删除某一行的SQL语句:DELETE FROM 表名 WHERE 某一行的一个条件          
    if(condition)
    {
        char buf[SIZE]="delete from book where ";
        strcat(buf,condition);
        int len=strlen(buf);
        if(mysql_real_query(&mysql,buf,len))
        {
            printf("mysql_real_query insert faile\n");
            return; 
        }
    }
}

void Select(const char* condition)   //查询信息
{
    //SQL语句的查询: select * from 表名 where 某一行的条件
    char buf[SIZE]={0};
    if(condition)
    {
        strcpy(buf,"select * from book where ");
        strcat(buf,condition);
    }
    else      //如果条件为假,打印全部内容
    {
        strcpy(buf,"select * from book");
    }
    int len=strlen(buf);
    if(mysql_real_query(&mysql,buf,len))
    {
        printf("mysql_real_query select faile\n");   //查询失败
        return ;
    }

    MYSQL_RES* res;   //用来指向结果集
    MYSQL_ROW row;    //用来获取某一行的值
    if(!(res=mysql_store_result(&mysql)))      //将结果集存储起来
    {
        printf("mysql_store_result faile\n");
        mysql_free_result(res);
        return;
    }
    unsigned int num=mysql_num_fields(res);    //获取结果表中的列数
    printf("%-5s\t %-10s\t %-10s\t %-20s\n","name","tel","mail","addr");
    while((row=mysql_fetch_row(res)))  //获取结果集中的每一行,失败或读完返回NULL
    {
        unsigned int i=0;
        for(i=0;i<num;i++)          //row相当于一个指针数组,每一个元素都是一个字段的值
        {
            printf("%s\t",row[i]);
        }
        printf("\n");
    }
    mysql_free_result(res);
}

void Update(const char* column,const char* condition )    //更新某一列的值
{
    //更新某一列的SQL语句:update 表名 set 列名=新的值, ... where 确定到某一行的条件 
    if(condition)
    {
        char buf[SIZE]="update book set ";
        strcat(buf,column);
        strcat(buf," where ");
        strcat(buf,condition);

        int len=strlen(buf);
        if(mysql_real_query(&mysql,buf,len))
        {
            printf("mysql_real_query update faile\n");
            return;
        }
    }
}

void menu()
{
    int i=0;
    while(1)
    {
        printf("0:exit\t 1:insert\t 2:delete\t 3:select\t 4:update\t 5:printBook\n");
        printf("choice->:");
        scanf("%d",&i);
        char buf[100]={0};
        char condition[100]={0};
        switch(i)
        {
        case 0:
            exit(1);
            break;
        case 1:
            printf("输入 (naem,tel,mail,addr) 的格式插入:\n ");
            scanf("%s",buf);
            Insert(buf);
            break;
        case 2:
            printf("输入 name=名字,tel=电话,... 的格式进行删除,至少有一个条件:\n");
            scanf("%s",buf);
            Delete(buf);
            break;
        case 3:
            printf("输入 name=名字,tel=电话,... 的格式确定要查找的行,至少有一个条件:\n");
            scanf("%s",condition);
            Select(condition);
            break;
        case 4:
            printf("输入 name=名字,tel=电话,... 的格式确定要更新的行,至少一个条件\n");
            scanf("%s",condition);
            printf("输入 name=新值,tel=新值,mail=新值,addr=新值 的格式确定要更新的列,至少更改一列:\n");
            scanf("%s",buf);
            Update(buf,condition);
            break;
        case 5:
            Select(NULL);     //打印所有信息
            break;
        default:
            break;
        }
    }
}

int main()
{
//密码是你自己的,MsgBook也是你自己的库
    Connect("localhost","root","****","MsgBook");
    menu();
    mysql_close(&mysql);
    return 0;
}

结果:
这里写图片描述

这里写图片描述

作者:LF_2016 发表于2017/3/25 20:52:47 原文链接
阅读:223 评论:0 查看评论

最小的矩形

$
0
0

牛牛在二维坐标系中画了N个点,且都是整点。现在牛牛想画出一个矩形,使得这N个点都在矩形内或者在矩形上。
矩形的边均平行于坐标轴。牛牛希望矩形的面积最小。请你帮助牛牛计算下最小矩形的面积。
输入描述:
首先输入一个正整数N表示点的个数(2 <= N <= 50)

接下来N行每行两个整数x, y,表示该点的坐标。绝对值均小于等于100.

输出描述:
一个整数表示最小矩形的面积。

输入例子:
2
0 1
1 0

输出例子:
1


代码如下:

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int[] x = new int[N];
        int[] y = new int[N];
        int min_y = Integer.MAX_VALUE;
        int max_y = Integer.MIN_VALUE;
        int max_x = Integer.MIN_VALUE;
        int min_x = Integer.MAX_VALUE;
        int j = 0;
        for ( int i = 0 ; i < 2 * N ; i++){
            if ( i % 2 == 0){
                x[j] = in.nextInt();
                if ( x[j] > max_x){
                    max_x = x[j];
                }
                if ( x[j] < min_x){
                    min_x = x[j];
                }
            }else{
                y[j] = in.nextInt();
                if ( y[j] > max_y){
                    max_y = y[j];
                }
                if ( y[j] < min_y){
                    min_y = y[j];
                }
                j++;
            }
        }
        System.out.print(Math.abs(max_x-min_x)*Math.abs(max_y-min_y));
        in.close();
    }

}
作者:qq_30091945 发表于2017/3/25 20:58:44 原文链接
阅读:62 评论:0 查看评论

字符串分类

$
0
0

牛牛有N个字符串,他想将这些字符串分类,他认为两个字符串A和B属于同一类需要满足以下条件:
A中交换任意位置的两个字符,最终可以得到B,交换的次数不限。比如:abc与bca就是同一类字符串。
现在牛牛想知道这N个字符串可以分成几类。
输入描述:
首先输入一个正整数N(1 <= N <= 50),接下来输入N个字符串,每个字符串长度不超过50。

输出描述:
输出一个整数表示分类的个数。

输入例子:
4
abcd
abdc
dabc
bacd

输出例子:
1


利用HashSet的特性,如果添加集合中已经存在的元素,集合大小不变。
代码如下:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in  = new Scanner(System.in);
        int N = in.nextInt();
        HashSet<String> set = new HashSet<>();
        for ( int i = 0 ; i < N ; i++){
            String str = in.next();
            char[] ch = str.toCharArray();
            Arrays.sort(ch);
            set.add(String.valueOf(ch));
        }
        System.out.print(set.size());
        in.close();
    }

}
作者:qq_30091945 发表于2017/3/25 21:15:36 原文链接
阅读:62 评论:0 查看评论

[框架]eclipse搭建ssm框架 一

$
0
0

虽然现在也做过一些项目,但是自己从头搭起来的框架几乎没有,所以这两天自己搭了一下ssm的框架,下面写一下框架的搭建过程。并且给出增删改查四条线来方便大家熟悉代码。

环境准备

maven3.2.3
eclipse luna Service Release(4.4.1)
jdk 1.7
tomcat7.0.40
我们需要的工具就是这些,版本影响其实不太大。

配置

一般来说,tomcat ,jdk ,maven一起配置就可以。windows->preferences->Server配置tomcat,顺便配置jdk,如图
这里写图片描述
这里写图片描述
到此步,tomcat配置完成
下面配置maven,选择菜单windows->preferences->Maven->User Settings,具体看自己的配置文件,将配置文件和maven文件夹都设置好,如图
这里写图片描述

新建maven项目

File->New->Maven Project 新建一个maven项目
这里写图片描述
选择文件夹
这里写图片描述
选择webapp,如果刚到这个页面不现实下面这些,把catalog选项换成Internal
这里写图片描述
给项目起个名字
这里写图片描述

最后,还有个index.jsp报错,我们需要引入Java EE的jar包即可。在pom.xml中引入:

    <!-- 导入java ee jar 包 -->  
    <dependency>  
        <groupId>javax</groupId>  
        <artifactId>javaee-api</artifactId>  
        <version>7.0</version>  
    </dependency>  

到现在为止,
一个maven项目就搭建完成了。

引入jar包

我们需要引入的jar包包括以下几种
spring核心包
mybatis核心包
spring-mybatis整合包
mysql连接包
jstl标签类
日志包
json解析包
下面是pom文件的内容

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.storm.ssm</groupId>
        <artifactId>maven-ssm</artifactId>
        <packaging>war</packaging>
        <version>0.0.1-SNAPSHOT</version>
        <name>maven-ssm Maven Webapp</name>
        <url>http://maven.apache.org</url>

        <properties>
            <!-- spring版本号 -->
            <spring.version>4.0.2.RELEASE</spring.version>
            <!-- mybatis版本号 -->
            <mybatis.version>3.2.6</mybatis.version>
            <!-- log4j日志文件管理包版本 -->
            <slf4j.version>1.7.7</slf4j.version>
            <log4j.version>1.2.17</log4j.version>
        </properties>


        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>


            <!-- spring核心包 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-oxm</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-tx</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <!-- mybatis核心包 -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
            <!-- mybatis/spring包 -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.2.2</version>
            </dependency>
            <!-- 导入java ee jar 包 -->
            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-api</artifactId>
                <version>7.0</version>
            </dependency>
            <!-- 导入Mysql数据库链接jar包 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.30</version>
            </dependency>
            <!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->
            <dependency>
                <groupId>commons-dbcp</groupId>
                <artifactId>commons-dbcp</artifactId>
                <version>1.2.2</version>
            </dependency>
            <!-- JSTL标签类 -->
            <dependency>
                <groupId>jstl</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
            <!-- 日志文件管理包 -->
            <!-- log start -->
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>


            <!-- 格式化对象,方便输出日志 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.1.41</version>
            </dependency>


            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
                <version>${slf4j.version}</version>
            </dependency>

            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>${slf4j.version}</version>
            </dependency>
            <!-- log end -->
            <!-- 映入JSON -->
            <dependency>
                <groupId>org.codehaus.jackson</groupId>
                <artifactId>jackson-mapper-asl</artifactId>
                <version>1.9.13</version>
            </dependency>
            <!-- 上传组件包 -->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.1</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.4</version>
            </dependency>
            <dependency>
                <groupId>commons-codec</groupId>
                <artifactId>commons-codec</artifactId>
                <version>1.9</version>
            </dependency>


        </dependencies>
        <build>
            <finalName>maven-ssm</finalName>
        </build>
    </project>

整合spring-mybatis

jdbc.properties

这个文件配置连接数据库的参数赋值等。

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost/ssmtest
    username=root
    password=123456
    #定义初始连接数  
    initialSize=0  
    #定义最大连接数  
    maxActive=20  
    #定义最大空闲  
    maxIdle=20  
    #定义最小空闲  
    minIdle=1  
    #定义最长等待时间  
    maxWait=60000

log4j.properties

    #定义LOG输出级别  
    log4j.rootLogger=INFO,Console,File  
    #定义日志输出目的地为控制台  
    log4j.appender.Console=org.apache.log4j.ConsoleAppender  
    log4j.appender.Console.Target=System.out  
    #可以灵活地指定日志输出格式,下面一行是指定具体的格式  
    log4j.appender.Console.layout = org.apache.log4j.PatternLayout  
    log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n  

    #文件大小到达指定尺寸的时候产生一个新的文件  
    log4j.appender.File = org.apache.log4j.RollingFileAppender  
    #指定输出目录  
    log4j.appender.File.File = logs/ssm.log  
    #定义文件最大大小  
    log4j.appender.File.MaxFileSize = 10MB  
    # 输出所以日志,如果换成DEBUG表示输出DEBUG以上级别日志  
    log4j.appender.File.Threshold = ALL  
    log4j.appender.File.layout = org.apache.log4j.PatternLayout  
    log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c]%m%n 

spring-mybatis.xml

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
        xmlns:context="http://www.springframework.org/schema/context"  
        xmlns:mvc="http://www.springframework.org/schema/mvc"  
        xsi:schemaLocation="http://www.springframework.org/schema/beans    
                            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
                            http://www.springframework.org/schema/context    
                            http://www.springframework.org/schema/context/spring-context-3.1.xsd    
                            http://www.springframework.org/schema/mvc    
                            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">  
      <!-- 自动扫描 -->  
        <context:component-scan base-package="com.cn.ssm" /> 
         <!-- 引入配置文件 -->  
        <bean id="propertyConfigurer"  
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
            <property name="location" value="classpath:jdbc.properties" />  
        </bean>  

        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"  
            destroy-method="close">  
            <property name="driverClassName" value="${driver}" />  
            <property name="url" value="${url}" />  
            <property name="username" value="${username}" />  
            <property name="password" value="${password}" />  
            <!-- 初始化连接大小 -->  
            <property name="initialSize" value="${initialSize}"></property>  
            <!-- 连接池最大数量 -->  
            <property name="maxActive" value="${maxActive}"></property>  
            <!-- 连接池最大空闲 -->  
            <property name="maxIdle" value="${maxIdle}"></property>  
            <!-- 连接池最小空闲 -->  
            <property name="minIdle" value="${minIdle}"></property>  
            <!-- 获取连接最大等待时间 -->  
            <property name="maxWait" value="${maxWait}"></property>  
        </bean>  

        <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->  
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
            <property name="dataSource" ref="dataSource" />  
            <!-- 自动扫描mapping.xml文件 -->  
            <property name="mapperLocations" value="classpath:com/cn/ssm/mapping/*.xml"></property>  
        </bean>  

        <!-- DAO接口所在包名,Spring会自动查找其下的类 -->  
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
            <property name="basePackage" value="com.cn.ssm.dao" />  
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>  
        </bean>  

        <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->  
        <bean id="transactionManager"  
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
            <property name="dataSource" ref="dataSource" />  
        </bean>  


        </beans>

到此为止,spring和mybatis的整合就完成了,下面做springmvc的整合。

整合springmvc

spring-mvc.xml

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans"  
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
        xmlns:context="http://www.springframework.org/schema/context"  
        xmlns:mvc="http://www.springframework.org/schema/mvc"  
        xsi:schemaLocation="http://www.springframework.org/schema/beans    
                            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
                            http://www.springframework.org/schema/context    
                            http://www.springframework.org/schema/context/spring-context-3.1.xsd    
                            http://www.springframework.org/schema/mvc    
                            http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">  
        <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->  
        <context:component-scan base-package="com.cn.ssm.controller" />  

        <!--避免IE执行AJAX时,返回JSON出现下载文件 -->  
        <bean id="mappingJacksonHttpMessageConverter"  
            class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">  
            <property name="supportedMediaTypes">  
                <list>  
                    <value>text/html;charset=UTF-8</value>  
                </list>  
            </property>  
        </bean>  
        <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->  
        <bean  
            class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
            <property name="messageConverters">  
                <list>  
                    <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 -->  
                </list>  
            </property>  
        </bean>  
        <!-- 定义跳转的文件的前后缀 ,视图模式配置-->  
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
            <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->  
            <property name="prefix" value="/WEB-INF/jsp/" />  
            <property name="suffix" value=".jsp" />  
        </bean>  

        <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->  
        <bean id="multipartResolver"    
            class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
            <!-- 默认编码 -->  
            <property name="defaultEncoding" value="utf-8" />    
            <!-- 文件大小最大值 -->  
            <property name="maxUploadSize" value="10485760000" />    
            <!-- 内存中的最大值 -->  
            <property name="maxInMemorySize" value="40960" />    
        </bean>   

    </beans>  

以上配置文件的路径如图:
这里写图片描述

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>Archetype Created Web Application</display-name>  
    <!-- Spring和mybatis的配置文件 -->  
    <context-param>  
        <param-name>contextConfigLocation</param-name>  
        <param-value>classpath:spring-mybatis.xml</param-value>  
    </context-param>  
    <!-- 编码过滤器 -->  
    <filter>  
        <filter-name>encodingFilter</filter-name>  
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
        <async-supported>true</async-supported>  
        <init-param>  
            <param-name>encoding</param-name>  
            <param-value>UTF-8</param-value>  
        </init-param>  
    </filter>  
    <filter-mapping>  
        <filter-name>encodingFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
    <!-- Spring监听器 -->  
    <listener>  
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
    </listener>  
    <!-- 防止Spring内存溢出监听器 -->  
    <listener>  
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>  
    </listener>  

    <!-- Spring MVC servlet -->  
    <servlet>  
        <servlet-name>SpringMVC</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <init-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>classpath:spring-mvc.xml</param-value>  
        </init-param>  
        <load-on-startup>1</load-on-startup>  
        <async-supported>true</async-supported>  
    </servlet>  
    <servlet-mapping>  
        <servlet-name>SpringMVC</servlet-name>  
        <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->  
        <url-pattern>/</url-pattern>  
    </servlet-mapping>  

    <servlet-mapping>  

      <servlet-name>default</servlet-name>  

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

</servlet-mapping>  

<servlet-mapping>  

      <servlet-name>default</servlet-name>  

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

</servlet-mapping>  

<servlet-mapping>  

      <servlet-name>default</servlet-name>  

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

</servlet-mapping>  
<servlet-mapping>  

      <servlet-name>default</servlet-name>  

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

</servlet-mapping>  

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

</web-app> 

需要注意的是,spring-mybatis和spring-mvc这两个配置文件里面涉及到路径的要改成自己的实际路径,不然会报错。

测试

框架搭建完成,然后我们连接数据库测试一下,下面是数据库创建语句

DROP TABLE IF EXISTS `user_t`;
CREATE TABLE `user_t` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(40) NOT NULL,
  `password` varchar(255) NOT NULL,
  `age` int(4) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=125556 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of user_t
-- ----------------------------
INSERT INTO `user_t` VALUES ('12', '123', '123', '14');
INSERT INTO `user_t` VALUES ('123', 'test', '123', '13');
INSERT INTO `user_t` VALUES ('11111', 'zahgnsan', '123', '23');
INSERT INTO `user_t` VALUES ('123456', 'username', '12id', '34');
INSERT INTO `user_t` VALUES ('125555', '123', '123', '14');

建表成功以后,我们使用mybatis的插件来生成接口和mapper的代码,可以参考这个博客:
http://blog.csdn.net/zhshulin/article/details/23912615
生成之后将文件拷贝到我们的目录下,如图:
这里写图片描述

然后我们从前台到后台写一条线,先写一个查询。敲之前记得先把maven更新一下。

IUserService.java

package com.cn.ssm.service;

import com.cn.ssm.pojo.User;

public interface IUserService {

    public User getUserById(int userId);

}

UserServiceImpl.java

package com.cn.ssm.service.impl;
import javax.annotation.Resource;
import javax.transaction.Transactional;
import org.springframework.stereotype.Service;
import com.cn.ssm.dao.UserMapper;
import com.cn.ssm.pojo.User;
import com.cn.ssm.service.IUserService;

@Service
@Transactional
public class UserServiceImpl implements IUserService {

    @Resource
    public UserMapper userMapper;

    public User getUserById(int userId) {
        // TODO Auto-generated method stub

        return this.userMapper.selectByPrimaryKey(userId);
    }

}

UserController.java

package com.cn.ssm.controller;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.cn.ssm.pojo.User;
import com.cn.ssm.service.IUserService;

@Controller
@RequestMapping("/user")
public class UserController {

    @Resource
    private IUserService userService;

    @RequestMapping("userShow")
    public String toIndex(HttpServletRequest request,Model model){
        int userId = Integer.parseInt(request.getParameter("id"));

        User user = userService.getUserById(userId);

        model.addAttribute("user", user);

        return "showUser";
    }

}

showUser.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>  
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
<html>  
  <head>  
    <title>测试</title>  
  </head>  

  <body>  
    ${user.userName}  
  </body>  
</html> 

显示

启动tomcat,然后在浏览器的地址栏输入http://localhost:8080/ssm/user/userShow?id=12
将ssm改成你的项目名称。
显示如图:
这里写图片描述

搭建这个框架,我基本上是参照这个博客来做的,因为觉得应该总结一下自己这两天的成功,所以写了这篇博客,不过大部分代码和原博客一样,所以大家可以去看看原博客,写的超级好。附链接:http://blog.csdn.net/zhshulin/article/details/37956105/
谢谢。

作者:u013036688 发表于2017/3/25 21:28:03 原文链接
阅读:86 评论:0 查看评论

IT痴汉的工作现状48-领导的决定

$
0
0

有许多看似不可思议的事情发生了,你有点想不通。但是你得知这是领导的决定,你也就只能服从。

每天要提xx个bug

突然有一天太君被拉去开会了,回来气嘟嘟的说:MD,真是疯了,让我们每天要提20个bug,这是死命令!

强人所难啊,我们的一个模块早已稳定下来了,每天都要提这么多bug,有点扯。

每天bug清零

之后的一天,伟仔也被拉去开会了,回来气嘟嘟的对大家说:MD,真是疯了,让我们每天都要bug清零,也是死命令!

悖论之后的水深火热生活与应对之道

虽然太君他们每天并不能都提20个bug,但是6、7个总是有的。而我们的开发任务一样不减,却要每天应对层出不穷的bug,苦不堪言。
将近两周的时间里,测试团队和开发团队每晚都要10点半下班。伟仔在这段时间都没有笑过,每天都苦着个脸。
娥姐有次对我说,之前每天都有笑脸的,这段时间却是愁容满面,真是太不对劲啊。

不单单是我们团队,整个项目群都陷入了痛苦挣扎中。
美其名曰是为了软件的质量,实则是引入了重大的危机。

大家也慢慢的达成一些默契,测试提一些用户体验相关的小问题,或者是UI相关的易改的问题,慢慢的,保证开发进度的前提下,应对这领导的决定。

又过了一段时间,条件渐渐放松了。每天只需把严重bug清零即可,测试也不用每天死板的必须提那么多bug了。

严重问题必须要解释

Bingley打电话过来,说有几个严重bug要我解释一下。
6个严重bug有三个是iOS的,我又把大雄拉进电话会议中。
Bingley是一个类似大PM助理的角色,本就不懂技术,向他解释这些实在够累够烦。
就这样,我和大雄用了一个半小时才解释完毕。最后听说他要向领导解释这些严重bug,真是担心是否能解释明白。
后来规定就定下了,严重bug必须要向领导当面解释清楚。
再后来,测试就不提严重bug了。

以后你若是有幸加入一个项目组,发现所有的bug都是一般或提示性的,而没有严重bug,没有致命bug,也许就会遇到我。

作者:lincyang 发表于2017/3/25 21:31:32 原文链接
阅读:61 评论:0 查看评论

创造新世界

$
0
0

众所周知计算机代码底层计算都是0和1的计算,牛牛知道这点之后就想使用0和1创造一个新世界!牛牛现在手里有n个0和m个1,给出牛牛可以创造的x种物品,每种物品都由一个01串表示。牛牛想知道当前手中的0和1可以最多创造出多少种物品。
输入描述:
输入数据包括x+1行:

第一行包括三个整数x(2 ≤ x ≤ 20),n(0 ≤ n ≤ 500),m(0 ≤ m ≤ 500),以空格分隔

接下来的x行,每行一个01串item[i],表示第i个物品。每个物品的长度length(1 ≤ length ≤ 50)

输出描述:
输出一个整数,表示牛牛最多能创造多少种物品

输入例子:
3 3 1
1
00
100

输出例子:
2


代码如下:

import java.util.Scanner;

public class Main {
    static int[] n = new int[21];
    static int[] m = new int[21];
    static int X;
    static int N;
    static int M;
    static int[][] dp = new int[501][501];

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        X = in.nextInt();
        N = in.nextInt();
        M = in.nextInt();
        for ( int i = 1 ; i <= X ; i++){
            String str = in.next();
            char[] ch = str.toCharArray();
            for ( int j = 0 ; j < ch.length ; j++){
                if ( ch[j] == '0'){
                    n[i]++;
                }else{
                    m[i]++;
                }
            }
        }

        //二维动态规划,背包问题
        for ( int i = 1 ; i <= X ; i++){
            for ( int j = N ; j >= n[i] ; j--){
                for ( int k = M ; k >= m[i] ; k--){
                    dp[j][k] = Math.max(dp[j][k], dp[j-n[i]][k-m[i]]+1);
                }
            }
        }
        System.out.print(dp[N][M]);
        in.close();
    }

}
作者:qq_30091945 发表于2017/3/25 21:41:19 原文链接
阅读:59 评论:0 查看评论

linux驱动开发之设备驱动基础概念

$
0
0

前言

上一节介绍了 linux 驱动开发中 module 的导出模块,在这一节中首先 linux 设备驱动开发中相关的概念,设备驱动的分类和学习过程中的重点和难点。

正文

计算机系统的硬件主要由 CPU 、存储器和外设组成,目前 CPU 内部往往集成了存储器和外设适配器,比如 ARM 芯片中继承的 UART 、I2C控制器、USB控制器、SDRAM 控制器以及片内的 RAM 和Flash。

驱动针对的对象是存储器和外设(包括 CPU 内部集成的存储器和外设) 而不是针对 CPU 核的。

Linux 将存储器和外设分为三大类:

  • 字符设备
  • 块设备、
  • 网络设备

字符设备是指那些必须以 串行 顺序依次进行访问的设备。比如:* 触摸屏、鼠标*
块设备可以任意顺序进行访问,以块为单位进行操作,比如硬盘等。
字符设备和块设备之前并没有明显的界限,Flash设备,符合块设备的特点,但是我们仍然可以把它作为一个字符设备。

另外一个设备分来方法中所称的 I2C驱动、USB驱动、PCI 驱动、LCD驱动等本身可纳入3个基础大类,但是对于这些复杂的设备,linux也定义了独特的驱动体系结构。

linux设备驱动和整个软硬件系统的关系

除网络设备外,字符设备和块设备都被映射到 linux 系统的文件和目录中,通过文件目录接口 open() 、read()、write()、close() 等可以访问字符设备和块设备。

应用程序可以使用 Linux 的系统调用接口变成,也可以使用 C 库函数进行编程。

linux设备驱动和整个软件系统的关系

linux设备驱动的重点和难点

  • 编写 Linux 设备驱动程序需要很好的硬件基础,懂得 SRAM、FLASH、SDRAM、磁盘的读写方式、UART、 I2C、USB 等设备的接口以及轮询、中断、DMA 的原理、PCI 总线的工作方式、以及CPU的内存管理单元 (MMU)等。

  • 编写 Linux 设备驱动程序需要良好的 C 语言基础,能灵活的利用 C 语言的结构体、指针、函数指针、以及内存的动态申请和释放等。

  • 编写 Linux 设备驱动程序需要有一定的 linux 内核基础,至少明白驱动和内核的接口。

  • 编写 Linux 设备驱动程序需要工程师有非常好的多任务并发控制和同步的基础,因为在驱动中会大量使用自旋锁、互斥、信号量、等待队列等并发和同步机制。

总结

linux 字符设备驱动是最常见的驱动,学习字符设备驱动,要在字符设备驱动的基础上,加深对 I2C 、USB 等驱动框架的理解;同时重点理解和学习 Linux设备驱动的重点和难点部分的内容,提供自己的能力。

参考文献

设备驱动开发详解 第二版 宋宝华

作者:u013377887 发表于2017/3/25 21:54:37 原文链接
阅读:60 评论:0 查看评论

maven(15),快照与发布,RELEASE与SNAPSHOT

$
0
0


发布RELEASE

用户A将代码打包发布到RELEASE仓库,具体操作参考上篇文章。用户B使用时,需要在pom.xml添加JAR包的依赖坐标。如果用户A将版本从1.0升级为2.0,用户B使用时也需要同时在pom.xml中修改坐标版本。但是RELEASE是稳定版本,是经过测试以后才会发布的,通常不会频繁的升级版本


快照SNAPSHOT

SNAPSHOT是不稳定版,可能是还在开发中的版本,在开发时用户A可能每天都会更新代码,可能会频繁的发布版本。而另一组用户B需要实时得到A的最新代码版本,以进行同步开发。如果使用RELEASE仓库需要不停的更换坐标,才能升级到最新版本。而SNAPSHOT仓库则不需要这样做,用户A和用户B都不用升级版本。用户A每次发布时会根据当时时间创建一个新的快照版本,之前的快照版本也会保留成为历史版本。用户B每次构建项目时会自动根据版本时间加载最新的JAR包,这种模式更加适合于多模块同步开发测试阶段


SNAPSHOT仓库用法

和RELEASE仓库类似,在pom.xml中设置快照仓库如下

	<distributionManagement>
		<snapshotRepository>
			<id>snapshot</id>
			<name>snapshot</name>
			<url>http://localhost:8081/repository/maven-snapshots/</url>
		</snapshotRepository>
	</distributionManagement>

同时设置version中的版本后面必须有 -SNAPSHOT,此后缀代表这是一个快照版

<version>1.0-SNAPSHOT</version> 

在setting.xml中设置用户名密码,id要和上面对应。和RELEASE一样

	<servers>
		<server>
			<id>snapshot</id>
			<username>admin</username>
			<password>admin123</password>
		</server>
	</servers>

运行nexus私服(参考前两篇),在eclipse中右击maven项目--运行方式--maven build...  在goals中输入deploy,运行。

在nexus界面中点击最上排的方块图标--browse--components菜单--maven-snapshots仓库。如下,我没有改坐标,连续发布了几次,可以发现name列和group列是完全一样的,version列根据发布时间不同自动在1.0后面加上了当前时间,以此区别不同版本


作者:wangb_java 发表于2017/3/25 22:23:41 原文链接
阅读:124 评论:0 查看评论

Struts2快速入门

$
0
0

Struts2框架的概述

Struts2是一种基于MVC模式的轻量级Web框架,它自问世以来,就受到了广大Web开发者的关注,并广泛应用于各种企业系统的开发中。目前掌握Struts2框架几乎成为Web开发者的必备技能之一。接下来将针对Struts2的特点、安装以及执行流程等内容进行详细的讲解。

什么是Struts2

先讲Struts2框架之前,我们得知道JavaEE一共有三层架构,如下:

架构名称 所使用框架
Web层 Struts2
Service层 Spring
Dao层 Hibernate

接下来我们就来解释什么是Struts2,可从度娘上摘抄如下字段:

Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个Servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts2是Struts的下一代产品,是在Struts1和WebWork的技术基础上进行了合并的全新的Struts2框架。其全新的Struts2的体系结构与Struts1的体系结构差别巨大。Struts2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts2可以理解为WebWork的更新产品。虽然从Struts1到Struts2有着太大的变化,但是相对于WebWork,Struts2的变化很小。

从以上这段话可得出如下两点结论:

  1. Struts2是应用在Web层的框架。
  2. Struts2是在Struts1和WebWork框架基础之上发展的全新的框架。

在介绍Struts2之前,先来认识一下Struts1。Struts1是最早的基于MVC模式的轻量级的Web框架,它能够合理的划分代码结构,并包含验证框架、国际化框架等多种实用工具框架。但是随着技术的进步,Struts1的局限性也越来越多的暴露出来。为了符合更加灵活、高效的开发需求,Struts2框架应运而生。
Struts2是Struts1的下一代产品,是在Struts1和WebWork技术的基础上进行合并后的全新框架(WebWork是由OpenSymphony组织开发的,致力于组件化和代码重用的J2EE Web框架,它也是一个MVC框架)。虽然Struts2的名字和Struts1相似,但其设计思想却有很大不同。实质上,Struts2是以WebWork为核心的,它采用拦截器的机制来处理用户的请求。这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts2可以理解为WebWork的更新产品。
Struts2拥有优良的设计和功能,其优势具体如下:

  • 项目开源,使用及拓展方便,天生优势。
  • 提供Exception处理机制。
  • Result方式的页面导航,通过Result标签很方便的实现重定向和页面跳转。
  • 通过简单、集中的配置来调度业务类,使得配置和修改都非常容易。
  • 提供简单、统一的表达式语言来访问所有可供访问的数据。
  • 提供标准、强大的验证框架和国际化框架。
  • 提供强大的、可以有效减少页面代码的标签。
  • 提供良好的Ajax支持。
  • 拥有简单的插件,只须放入相应的JAR包,任何人都可以扩展Struts2框架,比如自定义拦截器、自定义结果类型、自定义标签等,为Struts2定制需要的功能,不需要什么特殊配置,并且可以发布给其他人使用。
  • 拥有智能的默认设置,不需要另外进行繁琐的设置。使用默认设置就可以完成大多数项目程序开发所需要的功能。

上面列举的就是Struts2的一系列技术优势,只需对它们简单了解即可,在学习了后面的知识后,会慢慢对这些技术优势有更好的理解和体会。
那么除了Struts2之外,还有哪些优秀的WEB层框架呢?

常见的Web层框架

常见的Web层框架有:

  • Struts2
  • Struts1
  • WebWork
  • SpringMVC

Web层框架都会有一个特点,那就是基于前端控制器模式实现的。我们也可复习一下常见的Dao层框架有哪些?

  • Hibernate
  • MyBatis
  • DBUtils
  • Spring JDBC Template

Web层的框架都会基于前端控制器的模式

什么是前端控制器模式呢?我们来看下图,在图中传统方式的开发,有一次请求就会对应一个Servlet。这样会导致出先很多Servlet。而Struts2将所有的请求都先经过一个前端控制器,在前端控制器中实现框架的部分功能,剩下具体操作要提交到具体的Action中。那么所有的请求都会经过前端控制器,那用什么来实现前端控制器呢?过滤器就是最好的一个实现方式,因为需要所有的请求都可以被过滤器拦截,然后在过滤器中实现部分的功能。所以Struts2的前端控制器也是由过滤器来实现的。
这里写图片描述

这里写图片描述
了解这些之后,我们来进行一个Struts2的快速入门,来感受一下Struts2的优势吧!

Struts2快速入门

下载Struts2的开发包

Struts2的官网为:https://struts.apache.org/
这里写图片描述
我们这里使用struts-2.3.24版本的Struts2为大家讲解,下载好了以后需要进行解压。

解压Struts2的开发包

解压后的目录结构如下:
这里写图片描述
从图中可以看出,展示的是解压后的struts-2.3.24的目录结构,为了让大家对每个目录的内容和作用有一定的了解,接下来针对这些目录进行简单介绍,具体如下:

  • apps:该文件夹用于存放官方提供的Struts2示例程序,这些程序可以作为学习者的学习资料,可为学习者提供很好的参照。各示例均为war文件,可以通过zip方式进行解压。
  • docs:该文件夹用于存放官方提供的Struts2文档,包括Struts2的快速入门、Struts2的文档以及API文档等内容。
  • lib:该文件夹用于存放Struts2的核心类库,以及Struts2的第三方插件类库。
  • src:该文件夹用于存放该版本Struts2框架对应的源代码。

有了Struts2的开发环境,接下来我们可以进行Struts2的开发了。

创建一个Web工程引入相应JAR包

首先,需要我们创建一个Web工程,引入相关的Jar包文件。引入哪些Jar包呢?将struts-2.3.24框架目录中的lib文件夹打开,得到Struts2开发中可能用到的所有Jar包(此版本有107个Jar包)。实际的开发中,我们根本不用引入这么多的Jar包。
要进行Struts2的基本的开发,可以参考struts-2.3.24中的apps下的一些示例代码,其中struts2-blank.war是一个Struts2的空的工程。我们只需要将struts2-blank.war解压后进入到WEB-INF下的lib中查看。
这里写图片描述
这些包就是Struts2的基本的开发包了,那么这些包都是什么含义呢?Struts2项目依赖的基础Jar包说明:
这里写图片描述
从表中可以看出,此版本的Struts2项目所依赖的基础Jar包共13个。Struts2根据版本的不同所依赖的基础Jar包可能不完全相同,不过基本上变化不大,读者可以视情况而定。
需要注意的视是,通常使用Struts2的Web项目并不需要利用到Struts2的全部Jar包,因此没有必要一次将Struts2的lib目录下的全部Jar包复制到Web项目的WEB-INF/lib路径下,而是根据需要,再添加相应的Jar包。
那么Struts2的基本Jar包已经引入完成了,我们使用Struts2都是从页面发起请求到服务器,再由服务器处理请求,响应到页面的这个过程,接下来我们就从页面开始进行Struts2的开发吧。

编写一个Action

在src下创建一个包cn.itcast.action,在该包下新建一个UserAction的类。在这个类中编写一个公有的,返回值为String类型的方法,这个方法的名称叫做execute,且该方法没有任何参数(因为这个方法最终要被反射执行)。

/**
 * 作为一个action
 * @author 李阿昀
 *
 */
public class UserAction {

    public String execute() {
        return "ok";
    }

}

对于Servlet来说,每次访问Servlet的时候,都会执行Servlet里面的service()方法。而对于Action来说,每次访问Action的时候,默认执行Action里面名称为execute的方法。注意:创建方法的要求是方法不能有参数。
Action类编写好了以后,Struts2框架如何识别它就是一个Action呢?那么我们需要对Action类进行配置。

完成Action的配置

这个时候,我们还需要观察apps中的示例代码,在WEB-INF的classes目录下,有一个名称为struts.xml的文件,这个文件就是Struts2的配置文件。
我们在开发中需要将struts.xml文件引入到工程的src下,因为src下的内容发布到Web服务器就在WEB-INF下的classes中了。将struts.xml中的原有内容删除掉,然后配置上自己编写的Action类就可以了。配置内容如下:里面的具体的标签,我们会在后面的地方详细介绍。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>                                         <!-- namespace必须以/开头 -->
    <package name="demo1" extends="struts-default" namespace="/">
        <!-- name绝不能以/开头 -->
        <action name="user" class="cn.itcast.action.UserAction">
            <result name="ok">/user.jsp</result>                
        </action>
    </package>
</struts>

紧接着在WebRoot目录下创建一个页面——user.jsp,该页面的内容为:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>Hello Struts2!!!</h1>
</body>
</html>

至此,Action类已经配置好了,配置好了以后大家考虑一下,现在是否可以执行呢?其实现在还不行,因为之前我们介绍过,Web层的框架都有一个特点就是基于前端控制器的模式,这个前端控制器是由过滤器实现的,所以我们需要配置Struts2的核心过滤器。这个过滤器的名称是StrutsPrepareAndExecuteFilter。

配置核心过滤器

Struts2框架要想执行,所有的请求都需要经过这个前端控制器(核心过滤器),所以需要配置这个核心过滤器。因为这个过滤器完成了框架的部分的功能。那么我们接下来对过滤器进行配置。我们打开web.xml,在web.xml中进行如下配置:

<!-- 配置Struts2的过滤器 -->
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

至此,我们可在浏览器地址栏输入地址http://localhost:8080/struts2_day01/user.action,访问Action,即能出现如下界面:
这里写图片描述
注意:后缀名(.action),这个后缀名可以不写,建议写出来。
到这里Struts2的入门案例已经编写完成了,那么我们来总结下Struts2的整个流程。

Struts2开发流程分析

从客户端发送请求过来,先经过前端控制器(核心过滤器,StrutsPrepareAndExecuteFilter),过滤器中执行一组拦截器(一组拦截器,就会完成部分功能代码),到底哪些拦截器执行了呢?在Struts2中定义了很多拦截器,在其默认栈中的拦截器会得到执行,这个我们可以通过断点调试的方式测试,拦截器执行完成以后,就会执行目标Action,在Action中返回一个结果视图,根据result的配置进行页面的跳转。用图来表示即为:
这里写图片描述
以上就是Struts2的大致上的执行流程,我觉得我已经画的够清晰了,如果您认为上图不完整,可参考官网提供的图:
这里写图片描述

作者:yerenyuan_pku 发表于2017/3/26 0:56:48 原文链接
阅读:42 评论:0 查看评论

Jpanel更新面板内容

$
0
0

在实现一个添加商品的操作,而在添加完商品之后,原本面板内容不会显示当前添加的商品。所以就需要更新jpanel
可以执行以下操作

containerPanel.remove(childPanel);
containerPanel.addChildPanel();
public void addChildPanel(){
    childPanel=new Jpanel();
    //执行childPanel的更新操作
    containerPanel.add(childPanel);
}
//验证containerPanel容器及其组件
containerPanel.validate();
//重绘组件
containerPanel.repaint();
作者:su20145104009 发表于2017/3/26 18:33:08 原文链接
阅读:223 评论:0 查看评论

网易2017春招笔试 双核处理 01背包

$
0
0

               题目链接:双核处理

           思路:共有两个cpu,如果想让时间最少,即要使得max(cpu_time1, cpu_time2)最小,设所有任务的时间和为sum,那么至少需要sum/2的时间处理所有任务。因此如果能让两个cpu处理时间都接近于sum/2就能的到最优解。此时就转化为体积为sum/2,共有n个物体,代价为t[i],价值也是t[i],尽量多的装即可。

        此处需要提一下,由于可能sum很大,需要利用题目给出的“每个数都是1024的倍数”,将数字全部除以1024.

AC代码

#include <cstdio>
#include <cmath>
#include <cctype>
#include <algorithm>
#include <cstring>
#include <utility>
#include <string>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000") 
#define eps 1e-10
#define inf 0x3f3f3f3f
#define PI pair<int, int> 
typedef long long LL;
const int maxn = 4194304 / 1024 * 55 + 5;
int dp[maxn], a[55];

int main() {
	int n;
	while(scanf("%d", &n) == 1) {
		int sum = 0;
		for(int i = 1; i <= n; ++i) {
			scanf("%d", &a[i]);
			a[i] /= 1024;
			sum += a[i]; 
		}
		memset(dp, 0, sizeof(dp));
		for(int i = 1; i <= n; ++i) {
			for(int j = sum/2; j >= a[i]; --j) {
				dp[j] = max(dp[j], dp[j - a[i]] + a[i]);
			}
		}
		printf("%d\n", max(dp[sum/2], sum-dp[sum/2])*1024);
			
	}
	return 0;
} 

如有不当之处欢迎指出!
作者:flyawayl 发表于2017/3/26 19:09:31 原文链接
阅读:113 评论:0 查看评论

Java基础(五)OOP面向对象之(三) 面向对象思想总结

$
0
0

Java基础(五)OOP面向对象之(三) 面向对象思想总结

  • 封装
  • 继承
  • 多态

1. 继承总结

继承现象大总结:

  • 子类重写父类方法,调用子类方法;
  • 子类属性与父类同名(不管子类属性前修饰符如何均允许),如获取属性,看获取属性方法位置,如在父类中,获取的是父类属性,如在子类中,获取的是子类属性;(就近原则)
  • 子类私有方法与父类私有方法同名,如调用该方法,看私有方法被调用的位置,如在父类中,调用的是父类方法,如在子类中,调用的是子类方法;(就近原则)
  • 子类静态方法与父类静态方法同名,子类静态方法屏蔽父类静态方法。如调用该静态方法,看实例化对象时所声明的类型,如声明为父类,调用的是父类中静态方法,反之是子类中静态方法。
  • 子类中的成员变量不会被覆盖,无多态特性,需要注意!

2. 封装总结 关键字和权限关系总结

和C++不同的是,Java内的继承通常采取,单继承多实现的方式。
并且,继承通常采用的是public类型的继承。所以,其中的权限关系主要如下所示。

访问级别 访问控制修饰符 同类 同包 子类 不同的包
公开 public y y y y
受保护 protected y y y
默认 default y y
私有 private y

需要注意的是,继承从某种程度来说,是对于封装的一种破坏操作。

3. 多态总结

  • 调用子类的方法
package com.us.demo.extend;

class TransferBase{
    public void method(){
        System.out.println("Base");
    }
}
class TransExtend extends TransferBase{
    public void superMethod(){
        super.method();
    }
    public void method(){
        System.out.println("Trans");
    }
}
public class TransferExtendTest {
    public static void main(String []args){
        TransferBase trans = new TransExtend();
        trans.method();//调用的事故子类中的method方法
  • 如何调用父类被覆盖掉方法
    • 第一种: 子类 重现的方法中 使用 super关键字 去调用父类中的方法或属性;
    • 第二种:直接实例化 父类。
package com.us.demo.extend;

class TransferBase{
    public void method(){
        System.out.println("Base");
    }
}
class TransExtend extends TransferBase{
    public void superMethod(){
        super.method();
    }
    public void method(){
        System.out.println("Trans");
    }
}
public class TransferExtendTest {
    public static void main(String []args){
        TransferBase trans = new TransExtend();
        trans.method();
        ((TransferBase)trans).method();//没用 只有让指针重新指向父类的空间
        ((TransExtend)trans).superMethod();// 可以 但是违背了多态的思想 有点鸡肋

//      如果不是类内部,而是外部调用,比如你例子中的main方法,答案是 
//
//      不能。你不能调用已经被覆盖掉的父类的方法。 
//
//      这也是覆盖override的最初设计意图之一。 
//
//      大多数时候,覆盖父类意味着子类想做些特殊的处理。如果能够跳过子类的特殊处理,就会打开一个无法控制的缺口,会导致很多很多问题。 
//
//      唯一可以调用父类方法的地方,就只有类内部。子类自己控制,什么时候该调用父类,什么时候做自己的处理。
    }


}
作者:u010416101 发表于2017/3/26 19:21:53 原文链接
阅读:82 评论:0 查看评论

Java基础(八) Java修饰符及接口详解之(一)static/final/abstract关键字及接口的使用

$
0
0

Java基础(八) Java修饰符及接口详解之(一)static/final/abstract关键字及接口的使用

  • static 修饰符
  • final 修饰符
  • abstract 修饰符
  • 接口
  • 访问控制
  • == 和 equals() 的区别
  • 基本数据类型对应的包装类型
  • 内部类

1. static修饰符

static修饰符可以用来修饰类的成员变量、成员方法和代码块。

  • 用static修饰的成员变量表示静态变量,可以直接通过类名来访问;
  • 用static修饰的成员方法表示静态方法,可以直接通过类名来访问;
  • 用static修饰的程序代码表示静态代码块,当Java虚似机加载类时,就会执行该代码块;(且静态代码块,貌似只会执行一次。单例模式的实现方法之一)

    被static所修饰的成员变量和成员方法表明归某个类所有,它不依赖于类的特定实例,被类的所有实例共享。

1.1 static 变量

成员变量:定义在类里面、方法外面的变量, 分两种:

  • 实例变量;(例如: public Integer number;)
  • 静态变量;形式和实例变量类似,在实例变量前面加static关键字;(例如: public static Integer number)

    static变量和实例变量的区别:

  • static变量对于每个类而言在内存中只有一个,能被类的所有实例所共享;实例变量对于每个类的每个实例都有一份,它们之间互不影响;

  • Java虚拟机在加载类的过程中为static变量分配内存,实例变量在加载完类后创建对象时分配内存;
  • static变量可以直接通过类名访问,实例变量通过引用类型变量访问;
public class Counter {
    public int count1 = 0;
    public static int count2 = 0;

    public static void main(String[] args) {
        Counter counterA = new Counter();
        Counter counterB = new Counter();
        counterA.count1++;
        counterA.count2++;
        counterB.count1++;
        counterB.count2++;
    }
}
// 练习:统计一个类创建实例的个数; 
// 解答:设置一个静态变量,每创建一个实例。就将Count++;

1.2 static 方法

成员方法分为静态方法和实例方法。用static修饰的方法叫静态方法,或类方法。静态方法也和静态变量一样,不需要创建类的实例,可以直接通过类名来访问。

public class Sample1 {
    public static int add(int x, int y) {
        return x + y;
    }
}

public class Sample2 {
    public void method() {
        int result = Sample1.add(1, 2);
        System.out.println("result= " + result);
    }
}
  • static方法可以直接访问所属类的实例变量和实例方法,直接访问所属类的静态变量和静态方法;

    • 不能使用this关键字;
    • 不能使用super关键字,super关键字用来访问当前实例从父类中继承的方法和属性。super关键字与类的特定实例相关;
    • 静态方法必须被实现。静态方法用来表示某个类所特有的功能,这种功能的实现不依赖于类的具体实例,也不依赖于它的子类。既然如此,当前类必须为静态方法提供实现。
  • 父类的静态方法不能被子类覆为非静态方法。以下代码编译出错。

public class Base {
    public static void method() {
    }
}

public class Sub extends Base {
    public void method() {
    }// 编译出错
}
  • 父类的非静态方法不能被子类覆盖为静态方法;

1.3 static 代码块

类中可以包含静态代码块,它不存于任何方法中。在Java虚拟机中加载类时会执行这些静态代码块。如果类中包含多个静态代码块,那么Java虚拟机将按照它们在类中出现的顺序依次执行它们,每个静态代码块只会被执行一次。

(思考:什么时候JVM对一个类进行类加载? 答: 在进行New操作,也就是分配空间的时候,会进行类加载。)

package com.us.demo.map;

public class Sample {
    static int i = 5;
    static {//第一个静态代码块
           System.out.println("First Static code i="+i++);
    }
    static {//第二个静态代码块
           System.out.println("Second Static code i="+i++);
    }
    public static void main(String[] args) {
           Sample s1 = new Sample();
           Sample s2 = new Sample();
           System.out.println("At last, i= "+i);
    }
}
// 5 6 7 
//First Static code i=5
//Second Static code i=6
//At last, i= 7

类的构造方法用于初始化类的实例,而类的静态代码块则可用于初始化类,给类的静态变量赋初始值。
静态代码块与静态方法一样,也不能直接访问类的实例变量和实例方法,而必须通过实例的引用来访问它们。

1.4 new一个对象的时候JVM都做了那些事情

new一个对象的时候JVM都做了那些事情:
//Student s = new Student();

1.4.1 之前没有进行类加载(即:类的第一个对象)

  1. 类加载。子类加载,若存在父类,再进行父类加载;
  2. 初始化父类静态的属性(赋默认值),执行父类静态代码块;
  3. 初始化子类静态的属性(赋默认值),执行子类静态代码块;
  4. 分配内存空间,加载父类非静态成员/匿名代码块;
  5. 加载子类类非静态成员/匿名代码块;
  6. 父类构造器;
  7. 子类构造器;
  8. 返回内存地址。
package com.us.demo.map;

public class Test {
    public static void main(String[] args) {

        A a = new B();
    }
}

class A {
    protected String name = "lisi";
    static String a = "Fathera";
    int numberA = 0;
    static {
        System.out.println("A静态代码块: " + a);
    }
    public A() {
        System.out.println("父类构造器A");
        System.out.println("父类构造器A中调用test方法开始,由于子类重写过test方法所以这里执行子类的test方法");
        test();
        numberA = 1;
        System.out.println("numberA:" + numberA);
        System.out.println("父类构造器A中调用test方法结束");
    }
    public void test() {

    }

}

class B extends A {
    static String b = "SonB";
    static {
        System.out.println("A静态代码块: " + b);
    }
    private String name = "tom";
    {
        System.out.println("子类匿名代码块中:" + name);
    }
    public B() {
        System.out.println("子类构造器B");
    }
    public void test() {

        System.out.println("test方法中:this.name=" + this.name);
        System.out.println("test方法中:super.name=" + super.name);
    }
}
结果:
A静态代码块: Fathera
A静态代码块: SonB
父类构造器A
父类构造器A中调用test方法开始,由于子类重写过test方法所以这里执行子类的test方法
test方法中:this.name=null
test方法中:super.name=lisi
numberA:1
父类构造器A中调用test方法结束
子类匿名代码块中:tom
子类构造器B

结论:

  • 子类中的属性的显示赋值的时机 是在 父类构造器执行完之后和子类的匿名代码块执行之前的某个时候。
  • 父类构造器A中调用test方法开始,由于子类重写过test方法所以这里执行子类的test方法;需要注意这边貌似不是使用的是靠近原则?

1.4.2 之前已经进行了类加载

  1. 类加载。子类加载,若存在父类,再进行父类加载;
  2. 分配内存空间,加载父类非静态成员/匿名代码块;
  3. 加载子类类非静态成员/匿名代码块;
  4. 父类构造器;
  5. 子类构造器;
  6. 返回内存地址。

练习例子:StaticTest.java StaticTest2.java

1.5 静态导入

静态导入也是JDK5.0引入的新特性。

要使用静态成员(方法和变量)我们必须给出提供这个静态成员的类。使用静态导入可以使被导入类的静态变量和静态方法在当前类中可以直接使用,使用这些静态成员无需再在前面写上他们所属的类名。

import static java.lang.Math.random;
import static java.lang.Math.PI;;

public class Test {
    public static void main(String[] args) {
        // 之前是需要Math.random()调用的
        System.out.println(random());
        System.out.println(PI);
    }
}       

2. final修改符

final具有”不可改变的”含义,它可以修饰非抽象类、非抽象成员方法和变量。

  • 用final修饰的类不能被继承,没有子类;
  • 用final修饰的方法不能被子类的方法覆盖;
  • 用final修饰的变量表示常量,只能被赋一次值;

    final不能用来修饰构造方法,因为”方法覆盖”这一概念仅适用于类的成员方法,而不适用于类的构造方法,父类的构造方法和子类的构造方法之间不存在覆盖关系. 因此用final修饰构造方法是无意义的。

    ??(父类中用private修饰的方法不能被子类的方法覆盖,因此private类型的方法默认是final类型的。)

2.1 final类

继承关系的弱点是打破封装,子类能够访问父类的方法,而且能以方法覆盖的方式修改实现细节。在以下情况下,可以考虑把类定义为final类型,使得这个类不能被继承。

  • 子类有可能会错误地修改父类的实现细节;
  • 出于安全,类的实现细节不允许有任何改动;
  • 在创建对象模型时,确信这个类不会再被扩展;

    例如JDK中java.lang.String类被定义为final类型;public final class String

2.2 final方法

某些情况下,出于安全原因,父类不允许子类覆盖某个方法, 此时可以把这个方法声明为final类型。例如在java.lang.Object类中,getClass()方法为final类型。

2.3 final变量

final修饰的属性(成员变量)赋值的位置:

  • 非静态的成员变量

    • 声明的同时
    • 匿名代码块
    • 构造器(类中出现的所有构造器)
  • 静态的成员变量

    • 声明的同时 常量通常这样声明 public final static String variable
    • static代码块

    • final可以修饰静态变量、实例变量、局部变量;

    • final变量都必须显示初始化,否则会导致编译错误;
    • 静态变量,定义变量时进行初始化或者static代码块中赋值;
    • 实例变量,可以在定义变量时,或者在构造方法中进行初始化;
    • final变量只能赋一次值。
package com.us.demo.finalTest;

class Sample {
    private final int var1 = 1;
    public Sample() {
         var1 = 2;                //编译出错,不允许改变var1实例变量的值;
    }

    public void method(final int param) {
         final int var2 = 1;         
         var2++;                  //编译出错,不允许改变var2局部常量的值
         param++;                 //编译出错,不允许改变final类型参数的值;
    }
}
public class Test2 {

}
package com.us.demo.finalTest;
class Sample2 {
    final int var1; // 定义var1实例常量
    final int var2 = 0; // 定义并初始化var2实例常量
    Sample2() {
        var1 = 1; // 初始化var1实例常量
    }
    Sample2(int x) {
        var1 = x; // 初始化var1实例常量
    }
}     
public class Test {
    public static void main(String []args){
        Sample2 sm2 = new Sample2();
        System.out.println(sm2.var1);
    }
}

注意: final 对象赋值主要可以在2处: 声明初始化时/构造函数内。
练习 FinalTest.java

3. abstract修饰符

可用来修饰类和成员方法。

  • 用abstract修饰的类表示抽象类,抽象类不能实例化,即不允许创建抽象类本身的实例。没有用abstract修饰的类称为具体类,具体类可以被实例化。
  • 用abstract修饰的方法表示抽象方法,抽象方法没有方法体。抽象方法用来描述系统具有什么功能,但不提供具体的实现。没有abstract修饰的方法称为具体方法,具体方法具有方法体。(即抽象方法无方法体,具体方法有方法体。)

语法规则;

  • 抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类;
  • 没有抽象构造方法,也没有抽象静态方法;
  • 抽象类中可以有非抽象的构造方法;
  • 抽象类及抽象方法不能被final修饰符修饰。(因为需要被实现,也就是需要被继承。)

抽象类不允许实例化:思考原因? 因为其中方法体只有名称,但是无方法体。

package com.us.demo.abstractTest;

//定义一个抽象类
abstract class student{
    int a;
//  abstract int abstractA;// 报错
  //抽象方法
  public abstract void study();
  //非抽象方法
  public void work(){
      System.out.println("努力学习");
  }
}
class goodstudent extends student{
    int abstractA = 1;
  //必须要实现抽象方法,否则该类依然是个抽象类
  public void study(){
      System.out.println("好学生不学习");
  }
}
public class Test {
  public static void main(String[] args) {
      goodstudent s=new goodstudent();
      //调用实现的方法
      s.study();
      //调用从抽象类中继承的非抽象方法
      s.work();
  }
}

练习 AbstractTest.java

4. 接口

接口使用的目的:解决多重继承问题;例如Fish类继承Animal类,表明Fish是一种动物,但鱼同样也是一种食物,如何表示这种关系呢? 由于Java语言不支持一个类有多个直接的父类,因此无法用继承关系来描述鱼既是一种食物,又是一种动物,为了解决这一问题,Java语言引入接口类型,简称接口。一个类只能有一个直接的父类,但是可以实现多个接口。 采用这种方式,Java语言对多继承提供了有力的支持。

4.1 接口是抽象类的另外一种形式

抽象类抽象到极致就是接口,抽象类可存在有方法体的方法,接口中的方法全部为抽象方法;

4.2 接口中的所有方法均是抽象方法, 默认都是public、abstract类型的;

public interface A {
//    private void method3(); // 不合法
//   Illegal modifier for the interface method method3; only public & abstract are permitted
    void method1(); // 合法,默认为public、abstract类型
    public abstract void method2();// 合法,显示声明为public、abstract类型
}

4.3 接口中的成员变量默认都是public, static, final类型,必须被显式初始化;

public interface A {
    int CONST = 1; // 合法,CONST默认为public, static, final类型
    public static final int OPAQUE = 1; // 合法,显示声明为public static final 类型
}

4.4 接口中只能包含public, static, final类型成员变量和public、abstract类型的成员方法;

4.5 接口中没有构造方法,不能被实例化。

4.6 一个类只能继承一个直接的父类,但能实现多个接口。

4.7 抽象类和接口比较:

  • 相同点:
    • 都不能被实例化;
    • 都能包含抽象方法;
  • 不同点;
    • 抽象类中可以为部分方法提供默认的实现,从而避免子类中重复实现它们,提高代码的可重用性,而接口中只能包含抽象方法;
    • 一个类只能继承一个直接的父类,这个父类有可能是抽象类;但一个类可以实现多个接口,这是接口的优势所在。

简而言之,抽象类是 可能包含抽象方法的类;接口是 只能包含抽象方法和常量的一种结构类型。

练习:InterfaceTest.java InterfaceTest2.java

5. 访问控制

面向对象的基本思想之一是封装实现细节并且公开方法。Java语言采用访问控制修饰符来控制类及类的方法和变量的访问权限,从而只向使用者暴露方法,但隐藏实现细节。访问控制分4种级别。

访问级别 访问控制修饰符 同类 同包 子类 不同的包
公开 public y y y y
受保护 protected y y y
默认 default y y
私有 private y

成员变量、成员方法和构造方法可以处于4个访问级别中的一个;
顶层类只可以处于公开或默认访问级别;

注意:protected和default都有包访问权限(同包下可以访问)

练习:access目录下的测试代码

6. == 和 equals() 的区别

  • == : 比较的是,值是不是相等;基本数据类型比较的是值,引用类型比较的是地址值。
  • equals(Object o): Object类中的方法,所以,在每一个java类中,都会有这个方法,因为每一个java类都是直接或者间接的Object类的子类,会继承到这个方法。

    如果自己所写的类中已经重写了equals方法,那么就安装用户自定义的方式来比较俩个对象是否相等,如果没有重写过equal方法,那么会调用父类(Object)中的equals方法进行比较,也就是比较地址值。

  • 注意:equals(Object o)方法只能是一个对象来调用,然后参数也是要传一个对象的

    所以下面是错误的写法:
        int a = 1;
        a.equals(1);
        因为基本数据类型不是算是对象,不能调用方法
  • 如果是基本数据类型那么就用 == 比较

  • 如果是引用类型的话,想按照自己的方式去比较,就要重写这个类中的equals方法, 如果没有重写,那么equals和==比较的效果是一样的,都是比较引用的地址值

  • 如果是比较字符串,那么直接用equals就可以了,因为String类里面已经重写了equals方法,比较的时候字符串的内容,而不是引用的地址值了

    • toString(): Object类中的方法,所以,在每一个java类中,都会有这个方法,因为每一个java类都是直接或者间接的Object类的子类,会继承到这个方法
  • 当前用一个引用指向一个对象的时候,比如:Student s = new Student(),然后如果直接打印这个引用s,其实是调用了s.toString()方法,然后就会把这个引用里面的存放的堆区对象的地址值显示出来所以我们会常常在类中重写这个toString()方法,然后让这个类的引用按照我们要求来返回内容。

    • getClass():Object类中的方法,所以,在每一个java类中,都会有这个方法,并且这个方式final修饰的,不能被子类重写,这个方法可以返回某一个引用在运行的时候指向对象的类型。返回的是这个对象的类的字节码。(详见 解析Java中的字节码)
例如:Person p = new Student() 
//会输出:class com.briup.chap06.Student
//说明这个引用p在运行时指向的是Student这个类的对象
//注意这个引用p的类型是Person的(多态)
 System.out.println(p.getClass());
// 所以返回的是指向数据空间内 数据结构的 数据类型。

7. 基本数据类型对应的包装类型

基本数据类型 包装数据类型
boolean Boolean
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double

需要注意的是,有一句话说”Java内一切皆对象”。但是,基本数据类型不是对象。

基本数据类型的数据存在栈中,计算更加快速,比较时比较的是数值。

对象数据类型存在堆中,比较时比较的是地址。

如果,需要以其它条件进行比较的话,需要重写compare函数(Comparable接口),或者使用Comparactor比较器。

参考文献

[1] JAVA 堆栈 堆 方法区 静态区 final static 内存分配 详解
http://blog.csdn.net/peterwin1987/article/details/7571808

[2] Java对象的创建 —— new之后JVM都做了什么?
http://blog.csdn.net/rainnnbow/article/details/52149586

[3] Java类的加载顺序,父类和子类初始化的顺序和重写所遇到的上塑造型
http://blog.csdn.net/u012468263/article/details/50642767

[4] Java中父类和子类初始化顺序
http://blog.csdn.net/yuxin6866/article/details/53107578

[5] java抽象类和抽象方法之间的关系
http://www.cnblogs.com/zxxiaoxia/p/4175768.html

作者:u010416101 发表于2017/3/26 19:23:15 原文链接
阅读:87 评论:0 查看评论
Viewing all 35570 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>