【Vaadin教程】利用IDEA开发基于Vaadin网络聊天室程序

利用Vaadin,我们可以轻松的开发出丰富的web界面,像写Swing一样写GUI,感觉什么extjs之类的弱爆了!下面是我做的一个网络聊天室的例子,

浏览器要求支持WebSocket。我这里用的Chrome 41,IE11,服务器使用jetty7

Vaadin的运行库,请到官网下载。https://vaadin.com/home

不说了,我直接贴代码。附件在群里面,QQ群号:185441009


运行效果图。


项目结构,不会建项目的请看我之前的教程。




package com.chat.main;

import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.data.fieldgroup.FieldGroup;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.data.util.PropertysetItem;
import com.vaadin.data.validator.StringLengthValidator;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.StreamResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
import com.vaadin.ui.*;


/**登陆类
 * Created by Juyan on 2015/4/28.
 */

@Theme("chat")
@Push
public class Login extends UI {


  TextField usernameField, checkCodeField;
  Window loginWindow;
  Button button;
  Image image;
  StreamResource.StreamSource imageSource;
  StreamResource resource;
  FieldGroup fieldGroup;

  public void init(VaadinRequest request) {

    loginWindow = new Window(" 聊天室登陆");
    loginWindow.setResizable(false);
    loginWindow.center();
    loginWindow.setModal(true);
    loginWindow.setIcon(FontAwesome.USER);
    loginWindow.addCloseListener(closeEvent -> {
      JavaScript.eval("close()");
      getUI().close();
    });

    FormLayout formLayout = new FormLayout();
    formLayout.setSizeUndefined();
    formLayout.setMargin(true);
    formLayout.addStyleName("login-formlayout");


    usernameField = new TextField("请输入昵称:");

    button = new Button("登 陆");
    button.addClickListener(clickEvent -> {
      try {
        fieldGroup.commit();
        if (!checkCodeField.getValue().equals(VaadinSession.getCurrent().getAttribute("verifyCode").toString())) {
          Notification.show("验证码错误!", Notification.Type.ERROR_MESSAGE);
          changeChcekCode(request);
        } else {
          ChatWindow centerWindow = new ChatWindow(getUI(), request, loginWindow, usernameField.getValue());
          loginWindow.setVisible(false);
          getCurrent().addWindow(centerWindow);
        }
      } catch (FieldGroup.CommitException e) {
        e.printStackTrace();
      }
    });

    usernameField.addValidator(new StringLengthValidator("\"{0}\" 不是一个有效字符,昵称由2~10个字符组成。", 2, 10, false));
    checkCodeField = new TextField("验证码:");
    checkCodeField.addValidator(new StringLengthValidator("\"{0}\" 不是一个有效字符,验证码由4位字符组成。", 1, 4, false));

    usernameField.focus();

    image = new Image("", getChcekCodeSource(request));
    image.setDescription("点击刷新");
    image.setStyleName("v-check-code");
    image.addClickListener(clickEvent -> changeChcekCode(request));
    image.setErrorHandler(errorEvent -> errorEvent.getThrowable().printStackTrace());

    formLayout.addComponent(usernameField);
    formLayout.addComponent(checkCodeField);
    formLayout.addComponent(image);
    formLayout.addComponent(button);


    PropertysetItem propertysetItem = new PropertysetItem();
    propertysetItem.addItemProperty("username", new ObjectProperty<String>(""));
    propertysetItem.addItemProperty("checkCode", new ObjectProperty<String>(""));

    fieldGroup = new FieldGroup(propertysetItem);
    fieldGroup.bind(usernameField, "username");
    fieldGroup.bind(checkCodeField, "checkCode");

    loginWindow.setContent(formLayout);
    addWindow(loginWindow);
  }

  void changeChcekCode(VaadinRequest request) {
    image.setSource(getChcekCodeSource(request));
  }

  StreamResource getChcekCodeSource(VaadinRequest request) {

    imageSource = new CheckCodeImageSource(request);
    resource = new StreamResource(imageSource, System.currentTimeMillis() + ".png");
    resource.setCacheTime(0);
    return resource;
  }

}






package com.chat.main;

import com.chat.server.Broadcaster;
import com.vaadin.event.ShortcutAction;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.ui.*;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalTime;
import java.util.Date;

/** 聊天主窗口
 * Created by Juyan on 2015/5/4.
 */
public class ChatWindow extends Window implements Broadcaster.BroadcastListener {


  VerticalLayout root, messageLayout, receiverLayout, inputLayout;
  Panel showMessagePanel;
  VerticalSplitPanel splitPanel;
  Button sendButton;
  Window perantWindow;
  UI ui;
  String username;

  public ChatWindow(UI ui, VaadinRequest request, Window perant, String username) {
    this.ui = ui;
    this.perantWindow = perant;
    this.username = username;
    Broadcaster.register(this, request);
    initUI();
    initMessage();
  }

  void initUI() {

    addCloseListener(closeEvent -> {
      Broadcaster.unregister(this);
      perantWindow.setVisible(true);
    });


    setCaption(" 欢迎进入聊天室");
    setWidth("80%");
    setHeight("80%");
    setIcon(FontAwesome.USERS);
    setResizable(false);
    center();

    root = new VerticalLayout();
    root.setSizeFull();


    splitPanel = new VerticalSplitPanel();
    splitPanel.setSizeFull();

    messageLayout = new VerticalLayout();
    messageLayout.setMargin(true);
    messageLayout.setSizeFull();

    showMessagePanel = new Panel();
    showMessagePanel.setHeight("90%");
    messageLayout.addComponent(showMessagePanel);

    receiverLayout = new VerticalLayout();
    receiverLayout.setMargin(true);
    receiverLayout.setSpacing(true);
    receiverLayout.addStyleName("chat-spacing");

    showMessagePanel.setContent(receiverLayout);

    splitPanel.setFirstComponent(messageLayout);

    inputLayout = new VerticalLayout();
    inputLayout.setMargin(true);
    inputLayout.setSizeFull();

    TextArea textArea = new TextArea();
    textArea.setHeight("70%");
    textArea.setWidth("100%");

    sendButton = new Button("发 送");

    sendButton.setClickShortcut(ShortcutAction.ModifierKey.CTRL, ShortcutAction.KeyCode.ENTER);

    sendButton.addClickListener(clickEvent -> {

      SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
      String timeNow = simpleDateFormat.format(new Date());

      Broadcaster.broadcast("<font color=\"green\" style=\" font-weight:bold\">" + username + " " + timeNow + "</font></br>" + textArea.getValue());
      textArea.setValue("");
      textArea.focus();
    });

    inputLayout.addComponent(textArea);
    inputLayout.addComponent(sendButton);
    inputLayout.setComponentAlignment(sendButton, Alignment.TOP_RIGHT);

    splitPanel.setSecondComponent(inputLayout);

    splitPanel.setSplitPosition(75, Unit.PERCENTAGE);

    root.addComponent(splitPanel);
    setContent(root);
    textArea.focus();
  }

  void initMessage() {
    Broadcaster.broadcast("<font color=\"red\">【系统】欢迎 " + username + " 进入聊天室...</font");
  }

  void setMessage(String message) {
    receiverLayout.addComponent(new Label(message, ContentMode.HTML));
    showMessagePanel.setScrollTop(Integer.MAX_VALUE);
  }

  @Override
  public void receiveBroadcast(String message) {
    ui.access(() -> setMessage(message));
  }


}



package com.chat.main;

import com.vaadin.server.StreamResource;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Random;

/**验证码生成类
 * Created by Juyan on 2015/5/3.
 */
public class CheckCodeImageSource implements StreamResource.StreamSource {

  ByteArrayOutputStream byteArrayOutputStream;

  VaadinRequest request;

  public CheckCodeImageSource(VaadinRequest request) {

    this.request = request;

  }


  @Override
  public InputStream getStream() {

    // 在内存中创建图象
    int width = 70, height = 23;
    BufferedImage image = new BufferedImage(width, height,
        BufferedImage.TYPE_INT_RGB);
    // 获取图形上下文
    Graphics g = image.getGraphics();
    // 生成随机类
    Random random = new Random();
    // 设定背景色
    g.setColor(getRandColor(200, 250));
    g.fillRect(0, 0, width, height);
    // 设定字体
    g.setFont(new Font("Times New Roman", Font.PLAIN, 24));
    // 画边框
    g.setColor(getRandColor(160, 200));
    g.drawRect(0, 0, width - 1, height - 1);
    // 随机产生155条干扰线,使图象中的认证码不易被其它程序探测到
    g.setColor(getRandColor(160, 200));
    for (int i = 0; i < 155; i++) {
      int x = random.nextInt(width);
      int y = random.nextInt(height);
      int xl = random.nextInt(12);
      int yl = random.nextInt(12);
      g.drawLine(x, y, x + xl, y + yl);
    }
    // 取随机产生的认证码(4位数字)
    String sRand = "";
    for (int i = 0; i < 4; i++) {
      String rand = String.valueOf(random.nextInt(10));
      sRand += rand;
      // 将认证码显示到图象中
      g.setColor(new Color(20 + random.nextInt(110), 20 + random
          .nextInt(110), 20 + random.nextInt(110)));
      // 调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
      g.drawString(rand, 12 * i + 13, 20);
    }
    // 将认证码存入SESSION
    VaadinSession.getCurrent().setAttribute("verifyCode", sRand);
    // 图象生效
    g.dispose();
    byteArrayOutputStream = new ByteArrayOutputStream();
    try {
      ImageIO.write(image, "png", byteArrayOutputStream);
    } catch (IOException e) {
      e.printStackTrace();
    }
    return new ByteArrayInputStream(
        byteArrayOutputStream.toByteArray());
  }

  private Color getRandColor(int fc, int bc) {// 给定范围获得随机颜色
    Random random = new Random();
    if (fc > 255)
      fc = 255;
    if (bc > 255)
      bc = 255;
    int r = fc + random.nextInt(bc - fc);
    int g = fc + random.nextInt(bc - fc);
    int b = fc + random.nextInt(bc - fc);
    return new Color(r, g, b);
  }
}



package com.chat.server;

import com.vaadin.server.VaadinRequest;

import java.io.Serializable;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**广播类
 * Created by Juyan on 2015/5/5.
 */
public class Broadcaster implements Serializable {

  static ExecutorService executorService =
      Executors.newSingleThreadExecutor();

  public interface BroadcastListener {

    void receiveBroadcast(String message);
  }

  private static LinkedList<BroadcastListener> listeners =
      new LinkedList<BroadcastListener>();

  public static synchronized void register(
      BroadcastListener listener, VaadinRequest request) {
    listeners.add(listener);
    System.out.println("用户" + request.getRemoteHost() + "连接成功...");
  }

  public static synchronized void unregister(
      BroadcastListener listener) {
    listeners.remove(listener);
    System.out.println("用户退出...");
  }

  public static synchronized void broadcast(
      final String message) {
    for (final BroadcastListener listener : listeners)
      executorService.execute(() -> listener.receiveBroadcast(message));
  }
}




chat.scss

@import "../valo/valo.scss";

@mixin chat {
  @include valo;
}

.v-check-code {
  cursor: pointer;
}

.login-formlayout {
  margin: 20px;
}

.center-formlayout {
  margin: 200px;
}

.chat-spacing > .v-spacing {
  height: 20px;
}

.v-splitpanel-vsplitter {
  height: 5px !important;
}


styles.scss


@import "chat.scss";

@include chat;




web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

  <welcome-file-list>
    <welcome-file>/login/s.url</welcome-file>
  </welcome-file-list>

  <servlet>
    <servlet-name>VaadinApplicationServlet</servlet-name>
    <servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
    <init-param>
      <param-name>UI</param-name>
      <param-value>com.chat.main.Login</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>VaadinApplicationServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

</web-app>






转载于:https://my.oschina.net/qsyan/blog/411499

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值