信息收录项目

版权声明:本文为博主初学经验,未经博主允许不得转载。

一、前言

  记录在学习与制作WPF过程中遇到的解决方案。

   需求文案、设计思路、简要数据库结构、简要流程图和明细代码,动图细化每步操作,入门级引导文章;

   项目功能包括:登录、首页、数据维护 和 全文搜索等增删查改的常用操作;

二、配置

系统环境:win10

开发工具:Visual Studio 2017

开发语言:C#.WPF (MVVM框架)

数据库:SQLiteStudio

三、附件

四、项目需求

1. 项目背景:

前一段时间,一个老同事找到我说,有个项目一起搞,他负责营销,我负责平台;然后我就咨询了他关于项目的理念,听完通过电话聊天的述讲后,我只能呵呵一句,因为他还是着眼于眼前的需求,为了不打击他的激情,我不评论项目发展前景;完全配合他的计划,并加以我的思想完善整个项目趋势;接着就约了个时间详谈;通过茶水间的讨论后,才知道他只是要一个专属的OA平台而已,需求也甚是简单;因此我直接用该需求来作为项目制作的全过程指导文章;

2. 项目概述:  

文字描述:

  做一个信息搜索平台,平台主要角色是需求方信息,用户信息和解决需求的信息;
举例描述:

  我拿到一个厂家销售共享冰箱的项目,通过平台快速搜索到相关代理商和有共享方面销售的企业;
  或者厂家直接通过平台搜索有能力解决他商品销售的企业,然后通过平台联系,平台赚取中介费;
流程图描述:

3. 需求目标:  

把需求的数据有效统一整理,方便查阅,快速处理需求方和解决方的对接;
持久化有质量且高效的对接案例,从而能够为后续发展做铺垫;

4. 用户介绍

注册用户,游客,管理员;
用户类型包括厂家,小作坊,企业,商家,个人,代理商等等各种行业;

5. 功能

登录功能,搜索功能,数据维护的新增和编辑,数据的导出和导入,注册用户不能查阅其他用户维护的数据;

6. 项目制作时间规划

  .(个人单独开发).

7. 风险评估

由于经济条件,目前先制作离线本地版本,后期改进后再数据统一管理;

五、设计思路

使用MVVM的其中一个优点在于数据与视图的设计分离;

因此可以省略画草图,直接进行视图设计;

1. 登录页面

  登录输入包括账号和密码,密码用“*”号隐藏字符;输入框带有水印提示;

2. 注册页面

  注册输入包括账号,密码,手机号,邮箱,QQ等信息进行收录。同时,登录的时候也可以用账号、手机号、邮箱和QQ;

  由于注册页面的输入框做了一个自定义控件,所以在前端设计时并没有赋值,待完善后台代码,项目运行启动时自动赋值;

3. 数据维护页面

  维护数据包括公司名称,联系姓名,电话,邮箱,QQ,法人代表,法人联系方式,企业固话,传真,营业执照,税号,注册资本,等级资质,地址,销售物品相关,企业标签,公司简介,备注;

  百度了一下公司的组成信息就写了这些,备注算是补充字段了,后期再搞一个版本是自定义维护字段,这一期先不弄;

4. 导出页面

  根据时间,标签和销售相关进行数据导出;

5. 搜索页面

  模糊搜索,可以搜索所有字段信息;

  可以自定义列的显示,左边是搜索结果,右边是点击左边搜索结果的条目后,阅览更详细的信息;

  但更详细的信息中却隐藏了关键信息,拥有相关权限的用户点击联系客服后会显示关键信息,其他普通权限的用户只会以邮件的详细发给设置好的客服索取关键信息;

6. 设置页面

  关键信息设置隐藏,基础邮箱配置;

7. 样式使用的操作动图

六、数据库结构

1. 引用:

  Chloe.dll ; Chloe.SQLite ; System.Data.SQLite

2. SQLite的数据库常规操作的通用类

public class SqLiteSqlHelper
{
private readonly string _connectionString;
  public SqLiteSqlHelper()
{
_connectionString = DbConfiger.SqLiteConnectionString;
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="dbPath">SQLite数据库文件路径</param>
public SqLiteSqlHelper(string dbPath)
{
_connectionString = "Data Source=" + dbPath;
} /// <summary>
/// 对SQLite数据库执行增删改操作,返回受影响的行数。
/// </summary>
/// <param name="sql">要执行的增删改的SQL语句</param>
/// parameters 执行增删改语句所需要的参数,参数必须以它们在SQL语句中的顺序为准
public int ExecuteNonQuery(string sql, SQLiteParameter[] parameters)
{
int affectedRows;
using (var connection = new SQLiteConnection(_connectionString))
{
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction())
{
using (var command = new SQLiteCommand(connection))
{
command.CommandText = sql;
if (parameters != null)
command.Parameters.AddRange(parameters);
affectedRows = command.ExecuteNonQuery();
}
  transaction.Commit();
}
}
return affectedRows;
} /// <summary>
/// 执行一个查询语句,返回一个关联的SQLiteDataReader实例
/// </summary>
/// <param name="sql">要执行的查询语句</param>
/// parameters 执行SQL查询语句所需要的参数,参数必须以它们在SQL语句中的顺序为准
public SQLiteDataReader ExecuteReader(string sql,SQLiteParameter[] parameters)
{
var connection = new SQLiteConnection(_connectionString);
var command = new SQLiteCommand(sql, connection);
if (parameters != null)
{
command.Parameters.AddRange(parameters);
}
connection.Open();
return command.ExecuteReader(CommandBehavior.CloseConnection);
} /// <summary>
/// 执行一个查询语句,返回一个包含查询结果的DataTable
/// </summary>
public DataTable ExecuteDataTable(string sql, SQLiteParameter[] parameters)
{
using (var connection = new SQLiteConnection(_connectionString))
{
using (var command = new SQLiteCommand(sql, connection))
{
if (parameters != null)
command.Parameters.AddRange(parameters);
var adapter = new SQLiteDataAdapter(command);
var data = new DataTable();
adapter.Fill(data);
return data;
}
}
 } /// <summary>
/// 执行一个查询语句,返回查询结果的第一行第一列
/// </summary>
public object ExecuteScalar(string sql, SQLiteParameter[] parameters)
{
object obj;
using (var connection = new SQLiteConnection(_connectionString))
{
using (var command = new SQLiteCommand(sql, connection))
{
if (parameters != null)
command.Parameters.AddRange(parameters);
connection.Open();
obj = command.ExecuteScalar();
connection.Close();
}
}
return obj;
} /// <summary>
/// 查询数据库中的所有数据类型信息
/// </summary>
public DataTable GetSchema()
{
using (var connection = new SQLiteConnection(_connectionString))
{
connection.Open();
var data = connection.GetSchema("TABLES");
connection.Close();
return data;
}
}
}

判断表是否存在

public static bool IsExistsTable(string tableName)
{
var sql = string.Format(@"
            SELECT COUNT(*)
            FROM sqlite_master
            where type='table' and name='{0}';",
         tableName);
var count = new SqLiteSqlHelper().ExecuteScalar(sql, null);
return Convert.ToInt16(count) > ;
}

数据库数据用实体类操作

/// <summary>
/// SQLite数据访问
/// </summary>
private static readonly SqLiteDbProvider DbProvider = new SqLiteDbProvider(); /// <summary>
/// 获取用户数据
/// </summary>
public static List<Users> GetUsers(string id)
{
var result = DbProvider.DbContext.Query<Users>()
.Where(t => t.Id == id).ToList();
if (result != null) return result;
result = DbProvider.DbContext.Query<Users>()
.Where(t => t.UserCode == id
|| t.Phone == id
|| t.Email == id
|| t.Qq == id).ToList();
return result;
}

/// 更新用户数据
  public static void Delete(Contents content)
  {
     if (content == null) return;
     DbProvider.DbContext.Update<Contents>(t => t.Id == content.Id, t => content);
  }

 

3. 数据库表

  3.1 用户信息表

  3.2 企业信息表

  3.3 系统配置表

4. 库表关系

 

5.配套实体类写在Model层

  这里就不贴代码了,具体看源代码;

七、通用代码集

【GuidHelper】

/// 获取有序的唯一ID。
public static Guid GenerateComb(
SequentialGuidType sequentialGuidType = SequentialGuidType.SequentialAsString)
{
return SequentialGuidGenerator.NewSequentialGuid(sequentialGuidType);
}
// 根据枚举生成不同的有序GUID
private static class SequentialGuidGenerator
{
private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
public static Guid NewSequentialGuid(SequentialGuidType guidType)
{
var randomBytes = new byte[];
Rng.GetBytes(randomBytes);
var timestamp = DateTime.UtcNow.Ticks / 10000L;
var timestampBytes = BitConverter.GetBytes(timestamp);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(timestampBytes);
}
var guidBytes = new byte[];
switch (guidType)
{
case SequentialGuidType.SequentialAsString:
case SequentialGuidType.SequentialAsBinary:
Buffer.BlockCopy(timestampBytes, , guidBytes, , );
Buffer.BlockCopy(randomBytes, , guidBytes, , );
if (guidType == SequentialGuidType.SequentialAsString
            && BitConverter.IsLittleEndian)
{
Array.Reverse(guidBytes, , );
Array.Reverse(guidBytes, , );
}
break;
case SequentialGuidType.SequentialAtEnd:
Buffer.BlockCopy(randomBytes, , guidBytes, , );
Buffer.BlockCopy(timestampBytes, , guidBytes, , );
break;
}
return new Guid(guidBytes);
}
}
/// <summary>
/// 有序GUID的类型
/// sqlServer用AtEnd;
/// mysql用AsString或者AsBinary;
/// oracle用AsBinary;
/// postgresql用AsString或者AsBinary;
/// </summary>
public enum SequentialGuidType
{
SequentialAsString,
SequentialAsBinary,
SequentialAtEnd
}

【JsonHelper】

/// <summary>
/// 转换成JSON格式
/// </summary>
/// <typeparam name="T">转换类型</typeparam>
/// <param name="obj">string内容</param>
public static T ToJson<T>(this string obj) where T : class, new()
{
var model = new T();
var serializer = new DataContractJsonSerializer(model.GetType());
var mStream = new MemoryStream(Encoding.UTF8.GetBytes(obj));
return serializer.ReadObject(mStream) as T;
} /// <summary>
/// JSON转换String
/// </summary>
/// <typeparam name="T">转换类型</typeparam>
/// <param name="obj">Json内容</param>
public static string JsonToString<T>(this T obj)
{
var serializer = new DataContractJsonSerializer(obj.GetType());
var mStream = new MemoryStream();
serializer.WriteObject(mStream, obj);
byte[] dataBytes = new byte[mStream.Length];
mStream.Position = ;
mStream.Read(dataBytes, , (int) mStream.Length);
return Encoding.UTF8.GetString(dataBytes);
}

【LoggerHelper】

/// <summary>
/// 插入日志内容
/// </summary>
/// <param name="msg">内容</param>
public static void Insert(string msg)
{
Insert(msg, "Logger");
}
/// <summary>
/// 插入日志内容
/// </summary>
/// <param name="msg">内容</param>
/// <param name="logName">日志名称</param>
public static void Insert(string msg, string logName)
{
var name=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,logName+".dat");
using (var sw = new StreamWriter(name, true, Encoding.UTF8))
{
sw.WriteLineAsync($"{DateTime.Now} {msg}");
}
}

【TryCatch】

/// <summary>
/// 切换回主UI线程 并加Try Catch处理事件
/// </summary>
/// <param name="action">try里面的执行方法</param>
/// <param name="param">try里面的方法参数</param>
/// <param name="msg">系统异常</param>
/// <param name="workMsg">正常业务异常</param>
/// <param name="end">finally执行的事件</param>
public static void TryInvoke<T>(Action<T> action, T param,
  string msg = null, string workMsg = null, Action end = null)
{
try
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
action(param);
}));
}
catch (Common.BaseModels.WorkException e)
{
var errWord = workMsg ?? "业务异常";
var err = $"{errWord}:{e.Message}";
MessageBoxManager.ShowWorkError(err);
}
catch (Exception ex)
{
var errWord = msg ?? "系统异常";
var err = $"{errWord}:{ex.Message}";
Common.LoggerHelper.Insert(ex);
MessageBoxManager.ShowError(err);
}
finally
{
end?.Invoke();
}
}

【TabControlManager】(标签管理)

/// <summary>
/// 添加标签页子项
/// </summary>
public static void AddTabItem(TabControl tabControl, TabItem tabItem)
{
if (!IsContains(tabControl, tabItem, out var selectedIndex))
tabControl.Items.Add(tabItem);
tabControl.SelectedIndex = selectedIndex;
}
/// <summary>
/// 检查tabItem是否已经包含在了tabControl中
/// </summary>
public static bool IsContains(
    TabControl tabControl, TabItem tabItem, out int selectedIndex)
{
selectedIndex = ;
foreach (TabItem item in tabControl.Items)
{
if (item.Name == tabItem.Name)
return true;
selectedIndex++;
}
return false;
}

【ConvertHelper】

/// <summary>
/// 将原数据转为目标数据
/// 注:支持批量,但只支持列表接口子类,如:List
/// </summary>
public static TTo ConvertToTResult<TFrom, TTo>(
  TFrom t, DefaultMapConfig defaultMapConfig = null)
{
var mapper = ObjectMapperManager.DefaultInstance.GetMapper<TFrom, TTo>(
defaultMapConfig ?? new DefaultMapConfig());
return mapper.Map(t);
} public static TTo ConvertTo<TFrom, TTo>(
  this TFrom t, DefaultMapConfig defaultMapConfig = null)
{
var mapper = ObjectMapperManager.DefaultInstance.GetMapper<TFrom, TTo>(
defaultMapConfig ?? new DefaultMapConfig());
return mapper.Map(t);
} public static T Convert<T>(DataTable tb) where T : class
{
var lst = DataTableToEntity<T>(tb);
return lst.Any() ? lst.FirstOrDefault() : default(T);
} public static List<T> ConvertEnumToList<T>() where T : struct
{
return Enum.GetValues(typeof(T)).Cast<T>().ToList();
} /// <summary>
/// 将datatable转为实体
/// </summary>
public static IList<T> DataTableToEntity<T>(DataTable tb) where T : class
{
if (!HasRows(tb))
return new List<T>();
var lst = new List<T>();
foreach (DataRow item in tb.Rows)
{
var t = Activator.CreateInstance<T>();
foreach (DataColumn col in tb.Columns)
{
//先判断属性
var pi = t.GetType().GetProperty(col.ColumnName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
//再判断列
var objValue = item[col.ColumnName];
if (pi != null
&& pi.PropertyType == col.DataType
&& pi.CanWrite && (objValue != null
&& objValue != DBNull.Value))
{
pi.SetValue(t, objValue, null);
}
}
lst.Add(t);
}
return lst;
} /// <summary>
/// 将列头含有特殊字符的datatable转为实体
/// </summary>
/// <typeparam name="T">目标类型</typeparam>
/// <param name="tb">原数据table</param>
public static IList<T> DataTableToEntityWithColumnChar<T>(DataTable tb) where T : class
{
if (!HasRows(tb))
return new List<T>();
var lst = new List<T>();
foreach (DataRow item in tb.Rows)
{
var t = Activator.CreateInstance<T>();
foreach (DataColumn col in tb.Columns)
{
var tbColumnName = col.ColumnName;
var entityPropertyName = ReplaceSpecialChar(tbColumnName);
//先判断属性
var pi = t.GetType().GetProperty(entityPropertyName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
//再判断列
var objValue = item[tbColumnName];
if (pi != null
&& pi.PropertyType == col.DataType
&& pi.CanWrite && (objValue != null
&& objValue != DBNull.Value))
{
pi.SetValue(t, objValue, null);
}
}
lst.Add(t);
}
return lst;
}

【CloseableTabItem】

public delegate void CloseButtonDelegate(object sender, RoutedEventArgs e);
/// <summary>
/// 选项卡TabItem关闭时事件
/// </summary>
public event RoutedEventHandler TabItemClosing;
/// <summary>
/// 实例化标签项
/// </summary>
public CloseableTabItem(): this("New tab"){}
/// <summary>
/// 实例化标签项(给定标题)
/// </summary>
/// <param name="title">新标签项的标题字符串</param>
public CloseableTabItem(string title)
: this(title, SortWay.NotSort){} /// <summary>
/// 实例化标签项(给定标题,给定是否自动排序)
/// </summary>
/// <param name="title">标题</param>
/// <param name="sortWay"></param>
public CloseableTabItem(string title, SortWay sortWay)
{
//设定样式
Style = (Style) Application.Current.Resources["TabItemStyle"];
//生产一个可关闭的Header
var ctih = CreateCloseableTabItem();
//自动排序
switch (sortWay)
{
case SortWay.IsAutoSort:
break;
case SortWay.NotSort:
break;
}
//设定标题
ctih.Title = title;
//设定名称
Name = title;
//设定Header
Header = ctih;
} /// <summary>
/// 创建一个标签页头
/// </summary>
/// <returns>标签页头(自定义控件)</returns>
private PageTabItemHeader CreateCloseableTabItem()
{
//实例化一个Header
var ctih = new PageTabItemHeader();
//添加关闭按钮点击事件
ctih.BtnClose.Click += btnClose_Click;
//返回Header
return ctih;
} /// <summary>
/// 关闭按钮的点击事件处理方法
/// </summary>
private void btnClose_Click(object sender, RoutedEventArgs e)
{
// 触发标签项关闭事件
TabItemClosing?.Invoke(sender, e);
if (!e.Handled)
{
//关闭当前TabItem
GetParentObject<TabControl>(this).Items.Remove(this);
}
} /// <summary>
/// 获得指定元素的父元素
/// </summary>
/// <typeparam name="T">父级元素类型</typeparam>
/// <param name="obj">指定查找元素</param>
public T GetParentObject<T>(DependencyObject obj) where T : FrameworkElement
{
//返回可视对象的父对象
DependencyObject parent = VisualTreeHelper.GetParent(obj);
//按层、类型提取父级
while (parent != null)
{
if (parent is T)
return (T) parent;
parent = VisualTreeHelper.GetParent(parent);
}
//返回
return null;
}

Tab标签页制作跳转

前端:
<TabControl Name="TabControlGrid" TabStripPlacement="Top"
   Width="{Binding ElementName=Grid,Path=ActualWidth}"
   Height="{Binding ElementName=Grid,Path=ActualHeight}" >
<TabItem Header="Search">
<Frame Source="Content/Search.xaml" NavigationUIVisibility="Hidden">
<Frame.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="DarkSeaGreen" Offset=""/>
<GradientStop Color="White" Offset=""/>
</LinearGradientBrush>
</Frame.Background>
</Frame>
</TabItem>
</TabControl> 后端:
/// <summary>
/// 添加用户控件
/// </summary>
private CloseableTabItem AddUserControl(IFrameworkInputElement uc)
{
var ti = new CloseableTabItem(uc.Name) { Content = uc };
TabControlManager.AddTabItem(TabControlGrid, ti);
return ti;
}
/// <summary>
/// 添加Page页
/// </summary>
private void AddPage(IFrameworkInputElement uc)
{
var ti = new CloseableTabItem(uc.Name)
        {Content = new Frame {Content = uc}};
TabControlManager.AddTabItem(TabControlGrid, ti);
}
private void EditClick(object sender, RoutedEventArgs e)
{
AddPage(new Content.Edit());
}

八、项目手册

  贴图较多,查阅PPT;

九、下篇预告;

  MVC制作站点过程;

WPF项目学习.四的更多相关文章

  1. Spring Boot 项目学习 (四) Spring Boot整合Swagger2自动生成API文档

    0 引言 在做服务端开发的时候,难免会涉及到API 接口文档的编写,可以经历过手写API 文档的过程,就会发现,一个自动生成API文档可以提高多少的效率. 以下列举几个手写API 文档的痛点: 文档需 ...

  2. WPF项目学习.一

    WPF项目搭建 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 使用MVVM的优点是 数据和视图分离,双向绑定,低耦合,可重用行,相对独立 ...

  3. WPF项目学习.二

    WPF用MVVM的解决记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案.  焦点的控制,键盘事件触发,输入框的数字限制,异步处理,隐藏状 ...

  4. WPF项目学习.三

    工具代码记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 分页控件的制作,邮件发送,日志代码,excel导入导出等代码的实现过程: 二 ...

  5. WPF Binding学习(四) 绑定各种数据源

    转自:http://blog.csdn.net/lisenyang/article/details/18312199 1.集合作为数据源 首先我们先创建一个模型类 public class Stude ...

  6. Spring Boot 项目学习 (三) Spring Boot + Redis 搭建

    0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...

  7. Spring Boot 项目学习 (一) 项目搭建

    0 引言 本文主要记录借用Idea 开发环境下,搭建 Spring Boot 项目框架的过程. 1 系列文档目录 Spring Boot 项目学习 (一) 项目搭建 Spring Boot 项目学习 ...

  8. Spring Boot 项目学习 (二) MySql + MyBatis 注解 + 分页控件 配置

    0 引言 本文主要在Spring Boot 基础项目的基础上,添加 Mysql .MyBatis(注解方式)与 分页控件 的配置,用于协助完成数据库操作. 1 创建数据表 这个过程就暂时省略了. 2 ...

  9. 年度巨献-WPF项目开发过程中WPF小知识点汇总(原创+摘抄)

    WPF中Style的使用 Styel在英文中解释为”样式“,在Web开发中,css为层叠样式表,自从.net3.0推出WPF以来,WPF也有样式一说,通过设置样式,使其WPF控件外观更加美化同时减少了 ...

随机推荐

  1. centos7的服务管理

    1,启动服务(每条都可以)systemctl start httpdsystemctl start httpd.serviceservice httpd start 2,停止服务systemctl s ...

  2. Could not create the view: An unexpected exception was thrown的解决方法

    MyEclipse下面的server窗口突然不能正常显示了,而且还显示Could not create the view: An unexpected exception was thrown(无法创 ...

  3. 【Python】 用户图形界面GUI wxpython III 更多组件

    wxpython - 更多组件 我写到的这些组件可能一来不是很详细,二来不是最全的,想要更好地用这些组件,应该还是去看看教程和别的示例.比较简单的,推荐http://download.csdn.net ...

  4. 实现Windows程序的数据的绑定

    1.创建DataSet对象 语法: DataSet  数据集对象  =new  DataSet("数据集的名称字符串"); 语法中的参数是数据集的名称字符串,可以有,也可以没有.如 ...

  5. Hook 无侵入式埋点(页面统计)

    一.技术原理 Method-Swizzling 黑魔法 方法交换(不懂的可以查) 二.页面统计 某盟页面统计SDK需要开发者在APP基类里实现ViewDidAppear和viewDidDisappea ...

  6. 【Spring系列】Spring mvc整合druid

    一.pom.xml中添加druid依赖 <!-- druid --> <dependency> <groupId>com.alibaba</groupId&g ...

  7. Struts2——第一个helloworld页面

    struts2是一个较为成熟的mvc框架,先看看怎么配置struts2并且产生helloworld页面. 首先从官网下载struts2,http://struts.apache.org/downloa ...

  8. Linux下C编写基本的多线程socket服务器

    不想多说什么,会搜这些东西的都是想看代码的吧. 一开始不熟悉多线程的时候还在想怎么来控制一个线程的结束,后来发现原来有pthread_exit()函数可以直接在线程函数内部调用结束这个线程. 开始还想 ...

  9. SQLAlchemy 教程 —— 基础入门篇

    SQLAlchemy 教程 -- 基础入门篇 一.课程简介 1.1 实验内容 本课程带领大家使用 SQLAlchemy 连接 MySQL 数据库,创建一个博客应用所需要的数据表,并介绍了使用 SQLA ...

  10. 201621123057 《Java程序设计》第3周学习总结

    1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识点组织起来.请使用工具画出本周学习到的知识点及知识点之间的联系.步骤如下: 1.1 写出你 ...