一、简介
使用 Java Swing 开发日记管理系统
在今天的博客中,我将向您介绍如何使用 Java Swing 开发一个简单而功能强大的日记管理系统。这个系统将具有登录、注册、找回密码、写日志以及切换主题等功能。我们将使用 MySQL 数据库来存储用户信息和日记内容。
二、技术栈
- Java Swing:用于构建用户界面
- MySQL:用于存储用户信息和日记内容
- JDBC:用于 Java 与数据库的连接
- SQL:用于数据库操作
三、数据库设计
首先,我们来设计数据库表结构。每个用户将有一张日记表,用于存储他们的日记内容。以下是数据库表的创建语句:
-- 用户表
create table users(
username varchar(20) primary key,
displayname varchar(20),
pwd varchar(30),
mail varchar(30),
pwdprotectq int,
pwdprotecta varchar(50),
setting varchar(10) default 'summer'
);
-- 日记表示例
create table firstuser(
date char(10),
weather varchar(10),
emotion varchar(20),
title varchar(50),
content varchar(5000)
);
四、功能介绍
登录
用户可以使用他们的用户名和密码登录系统。我们将验证用户名和密码是否匹配数据库中的记录。
注册
新用户可以注册一个账号。他们需要提供用户名、显示名称、密码、邮箱地址以及密码保护问题和答案。
找回密码
如果用户忘记了密码,他们可以通过密码保护问题来找回密码。
写日志
用户可以添加新的日记条目。每个日记包括日期、天气、心情、标题和内容。
查看日记
切换主题
用户可以根据自己的喜好切换系统主题。我们提供了春夏秋冬四种主题,用户可以按照心情或天气对日记进行排序。
实现步骤
- 连接数据库:使用 JDBC 连接到 MySQL 数据库。
- 登录和注册界面:创建登录和注册界面,收集用户信息并验证。
- 密码找回界面:允许用户通过密码保护问题找回密码。
- 主界面:展示用户的日记列表,并提供写日记和切换主题的功能。
- 写日记界面:让用户输入日记内容并保存到数据库。
- 切换主题功能:根据用户选择的主题,改变界面的外观和排序方式。
五、部分代码
DateChooser.java
package qifang.li.diaryui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class DateChooser extends JPanel implements ActionListener, ChangeListener {
private static final long serialVersionUID = 1L;
int startYear = 1980;
int lastYear = 2050;
int width = 270;
int height = 200;
Color backGroundColor = Color.gray;
Color palletTableColor = Color.white;
Color todayBackColor = Color.orange;
Color weekFontColor = Color.blue ;
Color dateFontColor = Color.black;
Color weekendFontColor = Color.red ;
Color controlLineColor = Theme.getMainColor();
Color controlTextColor = Color.white ;
Color rbFontColor = Color.white ;
Color rbBorderColor = Color.red ;
Color rbButtonColor = Color.pink;
Color rbBtFontColor = Color.red ;
JDialog dialog;
JSpinner yearSpin;
JSpinner monthSpin;
JButton[][] daysButton = new JButton[6][7];
JFormattedTextField jFormattedTextField;//显示当前选择日期的格式化输入框
Calendar c = getCalendar();
Calendar cal = Calendar.getInstance();
int currentDay = cal.get(Calendar.DAY_OF_MONTH);
DateChooser(JFormattedTextField jftf){
jFormattedTextField = jftf;
setLayout(new BorderLayout());
setBorder(new LineBorder(backGroundColor,2));
setBackground(backGroundColor);
JPanel topYearAndMonth = createYearAndMonthPanal();
add(topYearAndMonth,BorderLayout.NORTH);
JPanel centerWeekAndDay = createWeekAndDayPanal();
add(centerWeekAndDay,BorderLayout.CENTER);
}
private JPanel createYearAndMonthPanal() {
int currentYear = c.get(Calendar.YEAR);
int currentMonth = c.get(Calendar.MONTH)+1;
JPanel result = new JPanel();
result.setLayout(new FlowLayout());
result.setBackground(controlLineColor);
yearSpin = new JSpinner(new SpinnerNumberModel(currentYear,startYear,lastYear,1));
yearSpin.setPreferredSize(new Dimension(60,20));
yearSpin.setName("Year");
yearSpin.addChangeListener(this);
result.add(yearSpin);
JLabel yearLabel = new JLabel("年");
yearLabel.setForeground(controlTextColor);
result.add(yearLabel);
monthSpin = new JSpinner(new SpinnerNumberModel(currentMonth,1,12,1));
monthSpin.setName("Month");
monthSpin.addChangeListener(this);
result.add(monthSpin);
JLabel monthLabel = new JLabel("月");
monthLabel.setForeground(controlTextColor);
result.add(monthLabel);
return result;
}
private JPanel createWeekAndDayPanal() {
String colname[] = {"日","一","二","三","四","五","六"};
JPanel result = new JPanel();
result.setFont(new Font("宋体",Font.PLAIN,12));
result.setLayout(new GridLayout(7,7));
result.setBackground(Color.white);
JLabel cell;
for(int i=0;i<7;i++) {
cell = new JLabel(colname[i]);
cell.setHorizontalAlignment(JLabel.CENTER);
if(i==0||i==6) {
cell.setForeground(weekendFontColor);
}else {
cell.setForeground(weekFontColor);
}
result.add(cell);
}
int actionCommandld = 0;
for(int i=0;i<6;i++) {
for(int j = 0;j<7;j++) {
JButton numberButton = new JButton();
numberButton.setBorder(null);
numberButton.setHorizontalAlignment(SwingConstants.CENTER);
numberButton.setActionCommand(String.valueOf(actionCommandld));
numberButton.addActionListener(this);
numberButton.setBackground(palletTableColor);
numberButton.setForeground(dateFontColor);
if(j ==0||j==6) {
numberButton.setForeground(weekendFontColor);
}else {
numberButton.setForeground(dateFontColor);
}
daysButton[i][j] = numberButton;
numberButton.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() ==2) {
closeAndSetDate();
}
}
});
result.add(numberButton);
actionCommandld++;
}
}
return result;
}
private JDialog createDialog(Frame owner) {
JDialog result = new JDialog(owner,"日期时间选择器",true);
result.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
result.getContentPane().add(this, BorderLayout.CENTER);
result.pack();
result.setSize(width, height);
return result;
}
public void showDateChooser(Point position) {
Object tmpobj = SwingUtilities.getWindowAncestor(jFormattedTextField);
if(tmpobj.getClass().isInstance(new JDialog())||tmpobj.getClass().getSuperclass().isInstance(new JDialog())) {
JDialog ownerdialog = (JDialog)SwingUtilities.getWindowAncestor(jFormattedTextField);
Frame owner = (Frame)SwingUtilities.getWindowAncestor(ownerdialog);
if(dialog == null || dialog.getOwner() != owner) {
dialog = createDialog(owner);
}
dialog.setLocation(getAppropriateLocation(owner,position));
}
else if(tmpobj.getClass().isInstance(new JFrame())||tmpobj.getClass().getSuperclass().isInstance(new JFrame())) {
JFrame ownerFrame = (JFrame)SwingUtilities.getWindowAncestor(jFormattedTextField);
if(dialog == null || dialog.getOwner() != ownerFrame) {
dialog = createDialog(ownerFrame);
}
dialog.setLocation(getAppropriateLocation(ownerFrame,position));
}
flushWeekAndDay();
dialog.setVisible(true);
}
Point getAppropriateLocation(Frame owner, Point position) {
Point result = new Point(position);
Point p = owner.getLocation();
int offsetX = (position.x + width) - (p.x = owner.getWidth());
int offsetY = (position.y + height) - (p.y + owner.getHeight());
if(offsetX > 0) {
result.x -= offsetX;
}
if(offsetY > 0) {
result.y -= offsetY;
}
return result;
}
public void closeAndSetDate() {
setDate(c.getTime());
dialog.dispose();
}
private Calendar getCalendar() {
Calendar result = Calendar.getInstance();
result.setTime(getDate());
return result;
}
private int getSelectedYear() {
return ((Integer)yearSpin.getValue()).intValue();
}
private int getSelectedMonth() {
return ((Integer)monthSpin.getValue()).intValue();
}
private void dayColorUpdate(boolean isOldDay) {
int day = c.get(Calendar.DAY_OF_MONTH);
c.set(Calendar.DAY_OF_MONTH, currentDay);
int actionCommandld = day -2 + c.get(Calendar.DAY_OF_WEEK);
int i = actionCommandld / 7;
int j = actionCommandld % 7;
if(isOldDay) {
daysButton[i][j].setForeground(dateFontColor);
}else {
daysButton[i][j].setForeground(todayBackColor);
}
}
private void flushWeekAndDay() {
c.set(Calendar.DAY_OF_MONTH,currentDay);
int maxDayNo = c.getActualMaximum(Calendar.DAY_OF_MONTH);
int dayNo = 2 - c.get(Calendar.DAY_OF_WEEK);
for(int i=0; i<6;i++) {
for(int j=0;j<7;j++) {
String s = "";
if(dayNo >= 1 && dayNo <= maxDayNo) {
s = String.valueOf(dayNo);
}
daysButton[i][j].setText(s);
dayNo++;
}
}
dayColorUpdate(false);
}
public void setDate(Date date) {
jFormattedTextField.setText(getDefaultDateFormat().format(date));
}
public Date getDate() {
try {
String dateString = jFormattedTextField.getText();
return getDefaultDateFormat().parse(dateString);
}catch(ParseException e){
return getNowDate();
}catch(Exception ee) {
return getNowDate();
}
}
private static Date getNowDate() {
return Calendar.getInstance().getTime();
}
private static SimpleDateFormat getDefaultDateFormat() {
return new SimpleDateFormat("yyyy-MM-dd");
}
@Override
public void stateChanged(ChangeEvent e) {
// TODO Auto-generated method stub
JSpinner source = (JSpinner)e.getSource();
dayColorUpdate(true);
if(source.getName().equals("Year")) {
c.set(Calendar.YEAR, getSelectedYear());
}
if(source.getName().equals("Month")) {
c.set(Calendar.MONDAY, getSelectedMonth()-1);
}
flushWeekAndDay();
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
JButton source = (JButton)e.getSource();
if (source.getText().length() == 0) {
return;
}
dayColorUpdate(true);
source.setForeground(todayBackColor);
int newDay = Integer.parseInt(source.getText());
c.set(Calendar.DAY_OF_MONTH, newDay);
}
}
FindPwdUI.java
package qifang.li.diaryui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
public class FindPwdUI {
private JPanel findPwdJP = new JPanel(){
private static final long serialVersionUID = 120000L;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
ImageIcon icon = Theme.getImage();
// 图片随窗体大小而变化
g.drawImage(icon.getImage(), 0, 0,getWidth(),getHeight(),this);
}
};
private JTextField userNameField = new JTextField();
private JPasswordField passwordField1 = new JPasswordField();
private JPasswordField passwordField2 = new JPasswordField();
String[] question = new String[] { "你父亲的名字是?", "你母亲的名字是?", "你的小名是?" ,"你最好的朋友是?","你最喜欢的颜色是?"};
private JComboBox questionSelector = new JComboBox(question);
private JTextField anwserField = new JTextField();
private JButton enterBn = new JButton("确定");
private JButton cancelBn = new JButton("取消");
public FindPwdUI() {
init();
}
public void clearFindPedPage() {
userNameField.setText("");
passwordField1.setText("");
passwordField2.setText("");
anwserField.setText("");
questionSelector.setSelectedIndex(0);
}
public void init() {
GridBagLayout gbLayout = new GridBagLayout();
GridBagConstraints gbCons = new GridBagConstraints();
findPwdJP.setLayout(gbLayout);
findPwdJP.setFocusable(false);
userNameField.addFocusListener(new JTextFieldHintListener(userNameField,"用户名6~20个字符"));
userNameField.setPreferredSize(new Dimension(200,30));
passwordField1.setPreferredSize(new Dimension(200,30));
passwordField2.setPreferredSize(new Dimension(200,30));
questionSelector.setPreferredSize(new Dimension(200,30));
anwserField.setPreferredSize(new Dimension(200,30));
gbCons.fill = GridBagConstraints.BOTH;
gbCons.insets = new Insets(10, 50, 5, 10);
gbCons.weightx = 0;
gbCons.weighty = 0;
gbCons.gridx = 0;
gbCons.gridy = 0;
gbCons.gridwidth = 1;
gbCons.gridheight = 1;
findPwdJP.add(new JLabel("用 户 名:"),gbCons);
Box nameBox = Box.createHorizontalBox();
gbCons.insets = new Insets(10, 0, 5, 50);
nameBox.add(userNameField);
gbCons.weightx = 1;
gbCons.gridx = 1;
findPwdJP.add(nameBox, gbCons);
gbCons.insets = new Insets(5, 50, 5, 10);
gbCons.weightx = 0;
gbCons.gridx = 0;
gbCons.gridy = 2;
findPwdJP.add(new JLabel("密保问题:"),gbCons);
gbCons.insets = new Insets(5, 0, 5, 50);
gbCons.weightx = 1;
gbCons.gridwidth = 1;
gbCons.weightx = 0;
gbCons.gridx = 1;
gbCons.gridy = 2;
findPwdJP.add(questionSelector,gbCons);
gbCons.insets = new Insets(5, 50, 5, 10);
gbCons.gridwidth = 1;
gbCons.weightx = 0;
gbCons.gridx = 0;
gbCons.gridy = 3;
findPwdJP.add(new JLabel("问题答案:"),gbCons);
Box Box6 = Box.createHorizontalBox();
gbCons.insets = new Insets(5, 0, 5, 50);
Box6.add(anwserField);
gbCons.weightx = 1;
gbCons.gridx = 1;
gbCons.gridy = 3;
findPwdJP.add(Box6, gbCons);
gbCons.insets = new Insets(5, 0, 5, 5);
gbCons.weightx = 0;
gbCons.gridx = 1;
gbCons.gridy = 4;
gbCons.gridwidth = 1;
findPwdJP.add(new JLabel("*密码长度8~30个字符,必须同时包含数字、字母、特殊字符"),gbCons);
gbCons.insets = new Insets(5, 50, 5, 10);
gbCons.weightx = 0;
gbCons.gridx = 0;
gbCons.gridy = 5;
gbCons.gridwidth = 1;
findPwdJP.add(new JLabel("新 密 码:"),gbCons);
Box Box2 = Box.createHorizontalBox();
gbCons.insets = new Insets(5, 0, 5, 50);
Box2.add(passwordField1);
gbCons.weightx = 1;
gbCons.gridx = 1;
gbCons.gridy = 5;
findPwdJP.add(Box2, gbCons);
gbCons.insets = new Insets(5, 50, 5, 10);
gbCons.weightx = 0;
gbCons.gridx = 0;
gbCons.gridy = 6;
findPwdJP.add(new JLabel("确认密码:"),gbCons);
Box Box3 = Box.createHorizontalBox();
gbCons.insets = new Insets(5, 0, 5, 50);
Box3.add(passwordField2);
gbCons.weightx = 1;
gbCons.gridx = 1;
gbCons.gridy = 6;
findPwdJP.add(Box3, gbCons);
gbCons.fill = GridBagConstraints.NONE;
gbCons.insets = new Insets(5, 50, 5, 10);
gbCons.weightx = 0;
gbCons.gridx = 0;
gbCons.gridy = 7;
enterBn.setBackground(Theme.getMainColor());
enterBn.setForeground(Color.white);
findPwdJP.add(enterBn,gbCons);
gbCons.anchor = GridBagConstraints.WEST;
gbCons.insets = new Insets(5, 0, 5, 50);
gbCons.weightx = 0;
gbCons.gridx = 1;
gbCons.gridy = 7;
cancelBn.setContentAreaFilled(false);
cancelBn.setForeground(Theme.getMainColor());
findPwdJP.add(cancelBn,gbCons);
}
public JTextField getUserNameField() {
return userNameField;
}
public void setUserNameField(JTextField userNameField) {
this.userNameField = userNameField;
}
public JPasswordField getPasswordField1() {
return passwordField1;
}
public void setPasswordField1(JPasswordField passwordField1) {
this.passwordField1 = passwordField1;
}
public JPasswordField getPasswordField2() {
return passwordField2;
}
public void setPasswordField2(JPasswordField passwordField2) {
this.passwordField2 = passwordField2;
}
public String[] getQuestion() {
return question;
}
public void setQuestion(String[] question) {
this.question = question;
}
public JComboBox getQuestionSelector() {
return questionSelector;
}
public void setQuestionSelector(JComboBox questionSelector) {
this.questionSelector = questionSelector;
}
public JTextField getAnwserField() {
return anwserField;
}
public void setAnwserField(JTextField anwserField) {
this.anwserField = anwserField;
}
public JButton getEnterBn() {
return enterBn;
}
public void setEnterBn(JButton enterBn) {
this.enterBn = enterBn;
}
public JButton getCancelBn() {
return cancelBn;
}
public void setCancelBn(JButton cancelBn) {
this.cancelBn = cancelBn;
}
public void setFindPwdJP(JPanel findPwdJP) {
this.findPwdJP = findPwdJP;
}
public JPanel getFindPwdJP() {
return findPwdJP;
}
}
Login.java
package qifang.li.diaryui;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
public class LoginUI {
private JPanel loginJP = new JPanel(){
private static final long serialVersionUID = 2L;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
ImageIcon icon = Theme.getImage();
// 图片随窗体大小而变化
g.drawImage(icon.getImage(), 0, 0,getWidth(),getHeight(),this);
}
};
private JTextField userNameField = new JTextField();
private JPasswordField passwordField = new JPasswordField();
private JButton loginBn = new JButton("登录");
private JButton signUpBn = new JButton("注册");
private JButton findBn = new JButton("找回密码");
public LoginUI() {
init();
}
public void init() {
userNameField.addFocusListener(new JTextFieldHintListener(userNameField,"用户名6~20个字符"));
GridBagLayout gbLayout = new GridBagLayout();
GridBagConstraints gbCons = new GridBagConstraints();
loginJP.setLayout(gbLayout);
loginJP.setFocusable(false);
gbCons.fill = GridBagConstraints.BOTH;
gbCons.insets = new Insets(20, 20, 10, 5);
gbCons.weightx = 0;
gbCons.weighty = 0;
gbCons.gridx = 0;
gbCons.gridy = 0;
gbCons.gridwidth = 1;
gbCons.gridheight = 1;
loginJP.add(new JLabel("用户名:"),gbCons);
Box nameBox = Box.createHorizontalBox();
gbCons.insets = new Insets(20, 5, 10, 5);
userNameField.setOpaque(false);
nameBox.add(userNameField);
gbCons.weightx = 1;
gbCons.gridx = 1;
loginJP.add(nameBox, gbCons);
gbCons.insets = new Insets(20, 5, 10, 20);
gbCons.weightx = 0;
gbCons.gridx = 2;
gbCons.gridy = 0;
signUpBn.setContentAreaFilled(false);
signUpBn.setForeground(Theme.getMainColor());
loginJP.add(signUpBn, gbCons);
gbCons.insets = new Insets(10, 20, 10, 5);
gbCons.gridx = 0;
gbCons.gridy = 1;
loginJP.add(new JLabel("密 码:"),gbCons);
Box pwdBox = Box.createHorizontalBox();
gbCons.insets = new Insets(10, 5, 10, 5);
passwordField.setOpaque(false);
pwdBox.add(passwordField);
gbCons.weightx = 1;
gbCons.gridx = 1;
gbCons.gridy = 1;
loginJP.add(pwdBox, gbCons);
gbCons.insets = new Insets(10, 5, 10, 20);
gbCons.weightx = 0;
gbCons.gridx = 2;
gbCons.gridy = 1;
findBn.setContentAreaFilled(false);
findBn.setForeground(Theme.getMainColor());
loginJP.add(findBn, gbCons);
gbCons.insets = new Insets(10, 5, 0, 5);
gbCons.weightx = 0;
gbCons.weighty = 0;
gbCons.gridx = 1;
gbCons.gridy = 2;
loginBn.setBackground(Theme.getMainColor());
loginBn.setForeground(Color.white);
loginJP.add(loginBn, gbCons);
userNameField.addMouseListener(new MouseFieldListener());
passwordField.addMouseListener(new MouseFieldListener());
}
class MouseFieldListener extends MouseAdapter{
@Override
public void mouseExited(MouseEvent e) {// 鼠标退出组件
((JTextField)e.getSource()).setBorder(BorderFactory.createLineBorder(Color.white));
}
@Override
public void mouseEntered(MouseEvent e) {// 鼠标进入组件
((JTextField)e.getSource()).setBorder(BorderFactory.createLineBorder(Theme.getMainColor()));
}
}
public JPanel getLoginJP() {
return loginJP;
}
public JButton getloginBn() {
return loginBn;
}
public JButton getSignUpBn() {
return signUpBn;
}
public JButton getFindBn() {
return findBn;
}
public JTextField getUserNameField() {
return userNameField;
}
public JTextField getPasswordField() {
return passwordField;
}
}
六、联系与交流
q:969060742 sql 、 完整代码、程序资源