using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public struct SegmentPoint
{
public Vector3 normal;
public Vector3 pos;
};
 
public class DrawMesh_Plane : MonoBehaviour {
 
MeshFilter meshFilter;
/// <summary>
/// 面片中的最后一个点
/// </summary>
SegmentPoint lastPoint;
SegmentPoint penultPoint;
 
bool startDraw = false;
bool twoPoint = false;
 
/// <summary>
/// 线条半径
/// </summary>
float r;
/// <summary>
/// 包含meshfilter、meshrenderer、材质球组件的预设体
/// </summary>
public GameObject linePrefab;
public Transform lineParent;
/// <summary>
/// 平滑点数
/// </summary>
public int smooth = 3;
 
[HideInInspector]
public Color lineColor;
 
public VRTracketObjManager vrtom;
public bool usePressure;
 
public DrawMeshManager drawMeshManager;
 
 
void Start()
{
lineColor = drawMeshManager.color;
}
 
 
void Update()
{
 
DrawMeshByCollider();
}
 
 
void DrawMeshVR()
{
var device = SteamVR_Controller.Input((int)vrtom.trackedObj_Left.index);
if (device.GetPress(SteamVR_Controller.ButtonMask.Trigger))
{
if (usePressure)
{
r = device.GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis1).x * drawMeshManager.brushRadius;
}
else
{
r = drawMeshManager.brushRadius;
}
if (!startDraw && !twoPoint)
{
GameObject line = Instantiate(linePrefab);
line.transform.SetParent(lineParent);
meshFilter = line.GetComponent<MeshFilter>();
line.GetComponent<MeshRenderer>().material.SetColor("_Color", lineColor);
if (drawMeshManager.addStep != null)
{
drawMeshManager.addStep(line);
}
}
float dis = Vector3.Distance(vrtom.leftPenPoint.position, lastPoint.pos);
if (!startDraw)
{
lastPoint.pos = vrtom.leftPenPoint.position;
lastPoint.normal = -vrtom.leftPenPoint.up;
startDraw = true;
}
else if (!twoPoint && dis > drawMeshManager.spaceDis)
{
SegmentPoint hitP;
hitP.pos = vrtom.leftPenPoint.position;
hitP.normal = -vrtom.leftPenPoint.up;
meshFilter.mesh = CreateStartMesh(lastPoint, hitP);
penultPoint = lastPoint;
lastPoint = hitP;
twoPoint = true;
}
else if (dis > drawMeshManager.spaceDis)
{
SegmentPoint hitP;
hitP.pos = vrtom.leftPenPoint.position;
hitP.normal = -vrtom.leftPenPoint.up;
SegmentPoint[] newSP = SmoothPoints(lastPoint, penultPoint, hitP);
List<Vector3> nv = new List<Vector3>();
for (int i = 0; i <= newSP.Length - 2; i++)
{
nv.AddRange(ComputeVertex(newSP[i], newSP[i + 1]));
}
penultPoint = newSP[newSP.Length - 2];
lastPoint = hitP;
SetMesh(nv.ToArray());
}
}
if (device.GetPressUp(SteamVR_Controller.ButtonMask.Trigger))
{
startDraw = false;
twoPoint = false;
meshFilter = null;
}
}
 
/// <summary>
/// 贴合模型画线
/// </summary>
void DrawMeshByCollider()
{
r = drawMeshManager.brushRadius;
if (Input.GetMouseButton(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit) && hit.collider.tag == TagManager.Line)
{
if (!startDraw && !twoPoint)
{
GameObject line = Instantiate(linePrefab);
line.transform.SetParent(lineParent);
meshFilter = line.GetComponent<MeshFilter>();
line.GetComponent<MeshRenderer>().material.SetColor("_Color", lineColor);
if (drawMeshManager.addStep != null)
{
drawMeshManager.addStep(line);
}
}
float dis = Vector3.Distance(hit.point, lastPoint.pos);
if (!startDraw) //开始创建第一个点
{
lastPoint.pos = hit.point;
lastPoint.normal = hit.normal;
startDraw = true;
}
else if (!twoPoint && dis > drawMeshManager.spaceDis) //开始创建第一个面片
{
SegmentPoint hitP;
hitP.pos = hit.point;
hitP.normal = hit.normal;
meshFilter.mesh = CreateStartMesh(lastPoint, hitP);
penultPoint = lastPoint;
lastPoint = hitP;
twoPoint = true;
}
else if (dis > drawMeshManager.spaceDis)
{
SegmentPoint hitP;
hitP.pos = hit.point;
hitP.normal = hit.normal;
SegmentPoint[] newSP = SmoothPoints(lastPoint, penultPoint, hitP);
List<Vector3> nv = new List<Vector3>();
for (int i = 0; i <= newSP.Length - 2; i++)
{
nv.AddRange(ComputeVertex(newSP[i], newSP[i + 1]));
}
penultPoint = newSP[newSP.Length - 2];
lastPoint = hitP;
SetMesh(nv.ToArray());
}
}
else
{
startDraw = false;
twoPoint = false;
meshFilter = null;
}
}
if (Input.GetMouseButtonUp(0))
{
startDraw = false;
twoPoint = false;
meshFilter = null;
}
}
 
/// <summary>
/// 创建第一个面片
/// </summary>
/// <param name="startP"></param>
/// <param name="endP"></param>
/// <returns></returns>
Mesh CreateStartMesh(SegmentPoint startP,SegmentPoint endP)
{
Vector3 v1 = endP.pos - startP.pos;
Vector3 d1 = Vector3.Cross(v1.normalized, startP.normal);
Vector3 d2 = Vector3.Cross(v1.normalized, endP.normal);
d1 = d1.normalized;
Vector3 p0, p1, p2, p3;
p0 = startP.pos - d1 * r * 0.5f + startP.normal * drawMeshManager.expand;
p1 = startP.pos + d1 * r * 0.5f + startP.normal * drawMeshManager.expand;
p2 = endP.pos - d2 * r * 0.5f + endP.normal * drawMeshManager.expand;
p3 = endP.pos + d2 * r * 0.5f + endP.normal * drawMeshManager.expand;
Vector3[] newVertices = {p0, p1, p2, p3 };
Vector2[] newUV = { new Vector2(p0.x, p0.y), new Vector2(p1.x, p1.y), new Vector2(p2.x, p2.y), new Vector2(p3.x, p3.y) };
int[] newTriangles = { 0, 1, 2, 1, 3, 2 };
Mesh mesh = new Mesh();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
return mesh;
}
 
 
/// <summary>
/// 获取原先面片
/// </summary>
/// <param name="vert"></param>
/// <param name="uvs"></param>
/// <param name="tri"></param>
void GetMesh(out List<Vector3> vert,out List<Vector2> uvs,out List<int> tri)
{
vert = new List<Vector3>();
uvs = new List<Vector2>();
tri = new List<int>();
vert.AddRange(meshFilter.mesh.vertices);
uvs.AddRange(meshFilter.mesh.uv);
tri.AddRange(meshFilter.mesh.triangles);
}
 
public void GenerateMesh(LineData ld)
{
GameObject l = Instantiate(linePrefab);
l.AddComponent<MeshFilter>();
l.AddComponent<MeshRenderer>();
l.transform.position = ld.position;
l.transform.eulerAngles = ld.rotation;
Vector3[] newVertices = ld.vertex;
Vector2[] newUV = ld.uv;
int[] newTriangles = ld.triangle;
Mesh mesh = new Mesh();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
l.GetComponent<MeshFilter>().mesh = mesh;
l.GetComponent<MeshRenderer>().material.color = ld.color;
}
 
/// <summary>
/// 使用贝塞尔平滑线段
/// </summary>
/// <param name="last"></param>
/// <param name="penult"></param>
/// <param name="current"></param>
/// <returns></returns>
SegmentPoint[] SmoothPoints(SegmentPoint last, SegmentPoint penult, SegmentPoint current)
{
float d = 1f / (float)smooth;
 
SegmentPoint[] ps = new SegmentPoint[smooth - 1];
for (int i = 0; i < ps.Length; i++)
{
float t = d * (i + 1);
ps[i].pos = (1 - t) * (1 - t) * penult.pos + 2 * t * (1 - t) * last.pos + t * t * current.pos;
ps[i].normal = Vector3.LerpUnclamped(penult.normal, current.normal, t);
}
List<SegmentPoint> segs = new List<SegmentPoint>();
segs.Add(penult);
segs.AddRange(ps);
segs.Add(current);
return segs.ToArray();
}
 
Vector3[] ComputeVertex(SegmentPoint p1,SegmentPoint p2)
{
Vector3 dir = p2.pos - p1.pos;
 
Vector3 d = Vector3.Cross(dir, p2.normal).normalized;
Vector3[] ps = new Vector3[2];
ps[0] = p2.pos - d * 0.5f * r + p2.normal * drawMeshManager.expand;
ps[1] = p2.pos + d * 0.5f * r + p2.normal * drawMeshManager.expand;
 
return ps;
}
 
/// <summary>
/// 添加mesh
/// </summary>
/// <param name="vetexes"></param>
void SetMesh(Vector3[] vertexes)
{
 
List<Vector3> vert;
List<Vector2> uvs;
List<int> tri;
GetMesh(out vert, out uvs, out tri);
Vector3[] newVert = vertexes;
Vector2[] newUv = new Vector2[vertexes.Length];
for (int i = 0; i < newVert.Length; i++)
{
newUv[i] = newVert[i];
}
 
vert.RemoveAt(vert.Count - 1);
vert.RemoveAt(vert.Count - 1);
vert.AddRange(newVert);
 
uvs.RemoveAt(uvs.Count - 1);
uvs.RemoveAt(uvs.Count - 1);
uvs.AddRange(newUv);
 
int[] newTri = new int[vert.Count * 3 - 6];
for (int i = 0; i < newTri.Length / 6; i++)
{
if (i == 0)
{
newTri[i] = 0;
newTri[i + 1] = 1;
newTri[i + 2] = 2;
newTri[i + 3] = 1;
newTri[i + 4] = 3;
newTri[i + 5] = 2;
}
else
{
newTri[i * 6] = newTri[i * 6 - 6] + 2;
newTri[i * 6 + 1] = newTri[i * 6 - 5] + 2;
newTri[i * 6 + 2] = newTri[i * 6 - 4] + 2;
newTri[i * 6 + 3] = newTri[i * 6 - 3] + 2;
newTri[i * 6 + 4] = newTri[i * 6 - 2] + 2;
newTri[i * 6 + 5] = newTri[i * 6 - 1] + 2;
}
}
Mesh m = new Mesh();
m.SetVertices(vert);
m.uv = uvs.ToArray();
m.triangles = newTri;
meshFilter.mesh.Clear();
meshFilter.mesh = m;
}
} =====================================================================
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;
using System.Text;
using System.IO;
using UnityEditor;
 
public class DrawMeshManager : MonoBehaviour {
 
/// <summary>
/// 线条半径
/// </summary>
public float brushRadius = 0.01f;
/// <summary>
/// 点之间最小间隔
/// </summary>
public float spaceDis = 0.04f;
/// <summary>
/// 面片向外扩展距离
/// </summary>
public float expand = 0.01f;
public Color color;
public float alpha;
 
public delegate void AddStep(GameObject gameObj);
public AddStep addStep;
 
/// <summary>
/// 最大保存步数
/// </summary>
public int maxCount = 10;
 
public GameObject line;
public GameObject tips;
 
List<GameObject> allLine = new List<GameObject>();
 
LineData[] allLineData ;
StringBuilder stringB;
string filepath;
 
// Use this for initialization
void Start () {
filepath = Application.dataPath + @"/StreamingAssets/json_line.txt";
addStep = new AddStep(AddDrawStep);
}
 
// Update is called once per frame
void Update () {
 
}
 
 
void AddDrawStep(GameObject mesh)
{
if (allLine.Count == maxCount)
{
allLine.RemoveAt(maxCount - allLine.Count);
}
allLine.Add(mesh);
}
 
void Undo()
{
if (Input.GetKeyDown(KeyCode.Z))
{
if (allLine.Count > 0)
{
Destroy(allLine[allLine.Count - 1]);
allLine.RemoveAt(allLine.Count - 1);
}
}
}
 
public void SaveI()
{
SaveAsyn();
}
 
 
void SaveAsyn()
{
allLineData = new LineData[line.transform.childCount];
print(allLineData.Length);
for (int i = 0; i < allLineData.Length; i++)
{
allLineData[i] = new LineData();
allLineData[i].name = line.transform.GetChild(i).name;
allLineData[i].position = line.transform.GetChild(i).position;
allLineData[i].rotation = line.transform.GetChild(i).eulerAngles;
allLineData[i].vertex = line.transform.GetChild(i).GetComponent<MeshFilter>().mesh.vertices;
allLineData[i].uv = line.transform.GetChild(i).GetComponent<MeshFilter>().mesh.uv;
allLineData[i].triangle = line.transform.GetChild(i).GetComponent<MeshFilter>().mesh.triangles;
allLineData[i].color = line.transform.GetChild(i).GetComponent<MeshRenderer>().material.color;
}
 
StringBuilder sb = LineData2Jason(allLineData);
stringB = sb;
 
 
//Loom.RunAsync(()=> { WriteToText(sb,filepath); });
WriteToText(sb, filepath);
//AssetDatabase.Refresh();
 
}
 
void WriteToText(StringBuilder sb,string filepath)
{
FileInfo t = new FileInfo(filepath);
if (!File.Exists(filepath))
{
File.Delete(filepath);
}
 
StreamWriter sw = t.CreateText();
sw.WriteLine(sb.ToString());
sw.Close();
sw.Dispose();
}
 
/// <summary>
/// 所有line转换为json
/// </summary>
/// <param name="ld"></param>
/// <returns></returns>
StringBuilder LineData2Jason(LineData[] ld)
{
StringBuilder sb = new StringBuilder();
JsonWriter writer = new JsonWriter(sb);
writer.WriteObjectStart();
writer.WritePropertyName("allLine");
writer.WriteArrayStart();
foreach (LineData data in ld)
{
writer.WriteObjectStart();
writer.WritePropertyName("name");
writer.Write(data.name);
 
writer.WritePropertyName("position");
writer.WriteArrayStart();
writer.WriteObjectStart();
writer.WritePropertyName("x");
writer.Write(data.position.x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.position.x.ToString("F5"));
writer.WritePropertyName("z");
writer.Write(data.position.x.ToString("F5"));
writer.WriteObjectEnd();
writer.WriteArrayEnd();
 
writer.WritePropertyName("rotation");
writer.WriteArrayStart();
writer.WriteObjectStart();
writer.WritePropertyName("x");
writer.Write(data.rotation.x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.rotation.y.ToString("F5"));
writer.WritePropertyName("z");
writer.Write(data.rotation.z.ToString("F5"));
writer.WriteObjectEnd();
writer.WriteArrayEnd();
 
writer.WritePropertyName("vertex");
writer.WriteArrayStart();
for (int i = 0; i < data.vertex.Length; i++)
{
writer.WriteObjectStart();
writer.WritePropertyName("index");
writer.Write(i.ToString());
 
writer.WritePropertyName("x");
writer.Write(data.vertex[i].x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.vertex[i].y.ToString("F5"));
writer.WritePropertyName("z");
writer.Write(data.vertex[i].z.ToString("F5"));
 
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
 
writer.WritePropertyName("uv");
writer.WriteArrayStart();
for (int i = 0; i < data.uv.Length; i++)
{
writer.WriteObjectStart();
writer.WritePropertyName("index");
writer.Write(i.ToString());
 
writer.WritePropertyName("x");
writer.Write(data.uv[i].x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.uv[i].y.ToString("F5"));
 
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
 
writer.WritePropertyName("triangle");
writer.WriteArrayStart();
for (int i = 0; i < data.triangle.Length; i++)
{
writer.WriteObjectStart();
writer.WritePropertyName("index");
writer.Write(i.ToString());
 
writer.WritePropertyName("value");
writer.Write(data.triangle[i].ToString());
 
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
 
writer.WritePropertyName("color");
writer.WriteArrayStart();
writer.WriteObjectStart();
writer.WritePropertyName("r");
writer.Write(data.color.r.ToString("F5"));
writer.WritePropertyName("g");
writer.Write(data.color.g.ToString("F5"));
writer.WritePropertyName("b");
writer.Write(data.color.b.ToString("F5"));
writer.WritePropertyName("a");
writer.Write(data.color.a.ToString("F5"));
writer.WriteObjectEnd();
writer.WriteArrayEnd();
 
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
writer.WriteObjectEnd();
return sb;
}
 
 
 
public void Read()
{
LineData[] ld;
 
StreamReader sr = File.OpenText(filepath);
string strLine = sr.ReadToEnd();
JsonData jd = JsonMapper.ToObject(strLine);
JsonData lineArray = jd["allLine"];
 
ld = new LineData[lineArray.Count];
 
for (int i = 0; i < lineArray.Count; i++)
{
ld[i] = new LineData();
JsonData name, px, py, pz, rx, ry, rz, cr, cg, cb, ca;
 
name = lineArray[i]["name"];
 
JsonData position = lineArray[i]["position"];
px = position[0]["x"];
py = position[0]["y"];
pz = position[0]["z"];
 
JsonData rotation = lineArray[i]["rotation"];
rx = rotation[0]["x"];
ry = rotation[0]["y"];
rz = rotation[0]["z"];
 
JsonData color = lineArray[i]["color"];
cr = color[0]["r"];
cg = color[0]["g"];
cb = color[0]["b"];
ca = color[0]["a"];
 
ld[i].name = (string)name;
 
ld[i].position.x = float.Parse((string)px);
ld[i].position.y = float.Parse((string)py);
ld[i].position.z = float.Parse((string)pz);
 
ld[i].rotation.x = float.Parse((string)rx);
ld[i].rotation.y = float.Parse((string)ry);
ld[i].rotation.z = float.Parse((string)rz);
 
ld[i].color.r = float.Parse((string)cr);
ld[i].color.g = float.Parse((string)cg);
ld[i].color.b = float.Parse((string)cb);
ld[i].color.a = float.Parse((string)ca);
 
JsonData vertex = lineArray[i]["vertex"];
ld[i].vertex = new Vector3[vertex.Count];
ld[i].uv = new Vector2[vertex.Count];
for (int j = 0; j < vertex.Count; j++)
{
ld[i].vertex[j] = new Vector3();
JsonData vx, vy, vz;
vx = vertex[j]["x"];
vy = vertex[j]["y"];
vz = vertex[j]["z"];
 
ld[i].uv[j] = new Vector2();
ld[i].vertex[j].x = float.Parse((string)vx);
ld[i].vertex[j].y = float.Parse((string)vy);
ld[i].vertex[j].z = float.Parse((string)vz);
 
ld[i].uv[j] = ld[i].vertex[j];
 
}
 
JsonData triangle = lineArray[i]["triangle"];
ld[i].triangle = new int[triangle.Count];
for (int j = 0; j < triangle.Count; j++)
{
ld[i].triangle[j] = int.Parse((string)triangle[j]["value"]);
}
 
}
CreateMesh(ld);
}
 
 
 
void CreateMesh(LineData[] ld)
{
for (int i = 0; i < ld.Length; i++)
{
//drawMesh.GenerateMesh(ld[i]);
}
}
 
}

Unity 绘制Mesh线条的更多相关文章

  1. Unity中Mesh分解与边缘高亮加上深度检测

    一个比较简单的需求,不过遇到些坑,记录下. 房间有多个模型,每个模型可能多个SubMesh,点击后,需要能具体到是那个SubMesh,并且在这个SubMesh上显示边缘高光,以及能个性这单个SubMe ...

  2. Quartz2D常见图形的绘制:线条、多边形、圆

    UI高级 Quartz2D http://ios.itcast.cn  iOS学院 掌握 drawRect:方法的使用 常见图形的绘制:线条.多边形.圆 绘图状态的设置:文字颜色.线宽等 图形上下文状 ...

  3. unity 绘制三角形

    哎 该学的还是要学 参考:http://www.narkii.com/club/thread-369573-1.html unity 顶点绘制三角形 脚本绘制; 其实filter和render就是进行 ...

  4. unity绘制线和绘制面

    绘制线条代码,其实就是指定至少两个点,然后赋予贴图即可,不废话,上代码: using UnityEngine; using System.Collections; public class LineT ...

  5. Unity 绘制多边形

    最近工程需要用到一个多边形用来查看角色属性,于是就研究了下Mesh用网格做了一个.遗憾的的 UGUI 渲染不了 3D 物体,然后又用了一段时间研究了下UGUI的网格绘制. 不过终于还是完成了,虽然有些 ...

  6. 关于Unity中Mesh网格的详解

    3D模型 通过3D建模软件所建出来的点和面,如以三角形为主的点和面,比如人的脑袋一个球,就是由各种各样的三角形组成的点和面. 点和面以及纹理坐标都是通过3D建模软件建模出来的. Unity会帮我们把模 ...

  7. Unity中用Mesh画一个圆环

    Probuider 前几天在做一个小项目的时候,用到了Unity自带的一个包ProBuilder其中的Arch生成1/4圆. 挺好玩的,可以在直接Unity中根据需要用Mesh定制生成图形,而不用建模 ...

  8. Unity - 绘制正五边形网格

    本文简述了Unity中绘制正五边形网格的基本方法:计算顶点信息.设置三角形覆盖信息.创建配置mesh 绘制方法 基本思路:计算出五边形顶点坐标信息作为数组,设置三角形包围方式,再创建新的mesh配置v ...

  9. Unity的Mesh压缩:为什么我的内存没有变化?

    0x00 前言 最近和朋友聊天,谈到了Mesh的内存优化问题,他发现开启Model Importer面板上的Mesh Compression选项之后,内存并没有什么变化.事实上,期望开启Mesh Co ...

随机推荐

  1. 记录Quarter的基本使用

    原文:记录Quarter的基本使用 using Quartz; using Quartz.Impl; using Quartz.Impl.Matchers; using Quartz.Logging; ...

  2. metasploit、msfvenom生成木马入侵电脑及手机

    简介 msfvenom msfvenom a Metasploit standalone payload generator,Also a replacement for msfpayload and ...

  3. HTML5的常用的标签

    HTML5对比HTML4新增了很多元素,也删除了部分元素(可以用css样式表方式替代)所以我只列出HTML5最常用的几个标签. head标签中: <meta http-equiv="X ...

  4. [React] 函数定义组件

    函数定义组件的例子 function Welcome(props) { return <h1>Hello, {props.name}</h1>; } 该函数是一个有效的 Rea ...

  5. 怎么对ZYNQ的FCLK做时钟组约束

    前言 对于包含PS和PL的设计,两者的数据交互PL必然会用到PS端的时钟. 对于FCLK(PS端时钟输入到PL端)的约束,此时钟的基础约束已在IP中产生.以下想约束其异步时钟的时钟组特性. 注意事项: ...

  6. Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流

    1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...

  7. pssh安装及使用

    pssh全称是parallel-ssh,基于Python编写的并发在多台服务器上批量执行命令的工具,它支持文件并行复制.远程并行执行命令.杀掉远程主机上的进程等:该工具可以视作ansible的简化版本 ...

  8. 【转】VC和VS的区别

    各个版本之间的对应关系 使用windows平台搞开发时,下载第三方库时经常会遇到文件名以VCxx版本号命令,VC版本如何转换成对应的VS的版本呢,这里总结一下vc和vs的关系. Microsoft V ...

  9. HTML&CSS基础-前端免费开发工具Hbuilder介绍

    HTML&CSS基础-前端免费开发工具Hbuilder介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 工欲善其事必先利其器,想要干好活得有一个好的工具. 一.文本编辑工 ...

  10. springboot 运行jar 跳转jsp页面

    pom.xml 添加 <!-- tomcat支持 --> <dependency> <groupId>org.springframework.boot</gr ...