@skills-cli/vue2-springboot-mybatis 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,8 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm install:*)",
5
+ "Bash(npm publish:*)"
6
+ ]
7
+ }
8
+ }
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @skills-cli/vue2-springboot-mybatis
2
+
3
+ Universal coding assistance skills for **Vue2 + SpringBoot + MyBatis** full-stack development. Provides code generation templates and helpers for rapid development.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ skills add @skills-cli/vue2-springboot-mybatis
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Vue2 Code Generation**
14
+ - Single-file component template
15
+ - CRUD list page with pagination
16
+ - Form modal component
17
+ - API service module
18
+
19
+ - **SpringBoot Code Generation**
20
+ - Controller layer with RESTful APIs
21
+ - Service layer with business logic interface
22
+ - Entity class with Lombok
23
+ - Mapper interface
24
+
25
+ - **MyBatis Code Generation**
26
+ - XML Mapper with CRUD operations
27
+ - Result map configuration
28
+ - Dynamic SQL support
29
+
30
+ ## Capabilities
31
+
32
+ - `generate-vue2-component` - Generate Vue2 single-file component
33
+ - `generate-vue2-crud-page` - Generate complete CRUD page (list + form + API)
34
+ - `generate-springboot-controller` - Generate SpringBoot REST Controller
35
+ - `generate-springboot-service` - Generate Service interface and implementation
36
+ - `generate-mybatis-entity` - Generate MyBatis entity class
37
+ - `generate-mybatis-mapper` - Generate Mapper interface
38
+ - `generate-mybatis-xml` - Generate MyBatis XML mapper
39
+ - `generate-crud-fullstack` - Generate full-stack CRUD from table definition
40
+
41
+ ## Usage Example
42
+
43
+ ```javascript
44
+ const skill = require('@skills-cli/vue2-springboot-mybatis');
45
+
46
+ // Generate Vue2 CRUD page
47
+ const vueCrud = skill.generateVue2Crud('User', 'user', [
48
+ { name: 'id', type: 'Long', label: 'ID', primaryKey: true },
49
+ { name: 'username', type: 'String', label: 'Username', required: true },
50
+ { name: 'email', type: 'String', label: 'Email' },
51
+ { name: 'createTime', type: 'Date', label: 'Create Time' }
52
+ ]);
53
+
54
+ // Generate SpringBoot Controller
55
+ const controller = skill.generateSpringBootController('User', 'user');
56
+
57
+ // Generate MyBatis Entity
58
+ const entity = skill.generateMyBatisEntity('User', columns);
59
+ ```
60
+
61
+ ## Configuration
62
+
63
+ You can configure in your `skills.json`:
64
+
65
+ ```json
66
+ {
67
+ "config": {
68
+ "@skills-cli/vue2-springboot-mybatis": {
69
+ "vue2": {
70
+ "componentPath": "src/components",
71
+ "viewPath": "src/views",
72
+ "apiPath": "src/api"
73
+ },
74
+ "springboot": {
75
+ "basePackage": "com.yourcompany.project",
76
+ "author": "Your Name"
77
+ }
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ ## API
84
+
85
+ ### Vue2 Generation
86
+
87
+ - `generateVue2Component(name, options)` - Generate Vue2 single-file component
88
+ - `generateVue2CrudPage(entityName, tableName, columns)` - Generate CRUD list page
89
+ - `generateVue2FormModal(entityName, columns)` - Generate form modal component
90
+ - `generateVue2Api(entityName, tableName)` - Generate API service module
91
+
92
+ ### SpringBoot Generation
93
+
94
+ - `generateMyBatisEntity(entityName, columns, packageName)` - Generate entity class
95
+ - `generateMyBatisMapper(entityName, packageName)` - Generate Mapper interface
96
+ - `generateSpringBootService(entityName, packageName)` - Generate Service
97
+ - `generateSpringBootController(entityName, packageName)` - Generate Controller
98
+ - `generateMyBatisXml(entityName, tableName, columns)` - Generate XML mapper
99
+
100
+ ### Full Stack
101
+
102
+ - `generateFullStackCrud(entityName, tableName, columns, config)` - Generate all files
103
+
104
+ ## License
105
+
106
+ MIT
package/index.js ADDED
@@ -0,0 +1,1035 @@
1
+ /**
2
+ * @skills-cli/vue2-springboot-mybatis
3
+ * Universal coding assistance skills for Vue2 + SpringBoot + MyBatis full-stack development
4
+ */
5
+
6
+ const skills = require('./skills.json');
7
+
8
+ /**
9
+ * Get skill information
10
+ */
11
+ function getInfo() {
12
+ return {
13
+ name: skills.name,
14
+ version: skills.version,
15
+ description: skills.description,
16
+ priority: skills.priority,
17
+ tags: skills.tags,
18
+ capabilities: skills.capabilities
19
+ };
20
+ }
21
+
22
+ /**
23
+ * Capitalize first letter
24
+ */
25
+ function capitalize(str) {
26
+ return str.charAt(0).toUpperCase() + str.slice(1);
27
+ }
28
+
29
+ /**
30
+ * camelCase to snake_case
31
+ */
32
+ function camelToSnake(str) {
33
+ return str.replace(/([A-Z])/g, '_$1').toLowerCase();
34
+ }
35
+
36
+ // ========== Vue2 Generation ==========
37
+
38
+ /**
39
+ * Generate Vue2 single-file component (.vue)
40
+ */
41
+ function generateVue2Component(componentName, options = {}) {
42
+ const { template = 'basic' } = options;
43
+ const compName = capitalize(componentName);
44
+
45
+ return `<template>
46
+ <div class="${componentName}-wrapper">
47
+ <!-- Component content -->
48
+ </div>
49
+ </template>
50
+
51
+ <script>
52
+ export default {
53
+ name: '${compName}',
54
+ components: {},
55
+ props: {},
56
+ data() {
57
+ return {};
58
+ },
59
+ computed: {},
60
+ watch: {},
61
+ created() {},
62
+ mounted() {},
63
+ methods: {}
64
+ };
65
+ </script>
66
+
67
+ <style scoped lang="scss">
68
+ .${componentName}-wrapper {
69
+
70
+ }
71
+ </style>
72
+ `;
73
+ }
74
+
75
+ /**
76
+ * Generate Vue2 CRUD list page
77
+ */
78
+ function generateVue2CrudPage(entityName, tableName, columns) {
79
+ const entityLower = entityName.toLowerCase();
80
+ const entityCapital = capitalize(entityName);
81
+
82
+ const searchForm = columns
83
+ .filter(col => !col.primaryKey && col.name !== 'createTime' && col.name !== 'updateTime')
84
+ .map(col => ` <el-form-item label="${col.label}">
85
+ <el-input v-model="searchForm.${col.name}" placeholder="Please enter ${col.label}" clearable />
86
+ </el-form-item>`)
87
+ .join('\n');
88
+
89
+ const tableColumns = columns
90
+ .map(col => ` <el-table-column prop="${col.name}" label="${col.label}"${col.width ? ` width="${col.width}"` : ''} />`)
91
+ .join('\n');
92
+
93
+ return `<template>
94
+ <div class="${entityLower}-page">
95
+ <!-- Search Form -->
96
+ <el-card class="search-card">
97
+ <el-form :inline="true" :model="searchForm" class="search-form">
98
+ ${searchForm}
99
+ <el-form-item>
100
+ <el-button type="primary" @click="handleSearch">Search</el-button>
101
+ <el-button @click="handleReset">Reset</el-button>
102
+ </el-form-item>
103
+ </el-form>
104
+ </el-card>
105
+
106
+ <!-- Toolbar -->
107
+ <el-card class="toolbar-card">
108
+ <el-button type="primary" icon="el-icon-plus" @click="handleAdd">Add ${entityCapital}</el-button>
109
+ </el-card>
110
+
111
+ <!-- Data Table -->
112
+ <el-card>
113
+ <el-table :data="tableData" border loading="loading">
114
+ ${tableColumns}
115
+ <el-table-column label="Operation" width="180" fixed="right">
116
+ <template slot-scope="scope">
117
+ <el-button size="mini" type="primary" @click="handleEdit(scope.row)">Edit</el-button>
118
+ <el-button size="mini" type="danger" @click="handleDelete(scope.row)">Delete</el-button>
119
+ </template>
120
+ </el-table-column>
121
+ </el-table>
122
+ <div class="pagination-wrapper">
123
+ <el-pagination
124
+ @size-change="handleSizeChange"
125
+ @current-change="handleCurrentChange"
126
+ :current-page="pagination.current"
127
+ :page-sizes="[10, 20, 50, 100]"
128
+ :page-size="pagination.size"
129
+ layout="total, sizes, prev, pager, next, jumper"
130
+ :total="pagination.total">
131
+ </el-pagination>
132
+ </div>
133
+ </el-card>
134
+
135
+ <!-- Add/Edit Dialog -->
136
+ <${entityLower}-form-dialog
137
+ :visible.sync="dialogVisible"
138
+ :form-data="currentRow"
139
+ :is-edit="isEdit"
140
+ @success="handleDialogSuccess"
141
+ />
142
+ </div>
143
+ </template>
144
+
145
+ <script>
146
+ import { ${entityLower}List, ${entityLower}Delete } from '@/api/${entityLower}';
147
+ import ${entityLower}FormDialog from './components/${entityLower}FormDialog.vue';
148
+
149
+ export default {
150
+ name: '${entityCapital}Page',
151
+ components: { ${entityLower}FormDialog },
152
+ data() {
153
+ return {
154
+ searchForm: {
155
+ ${columns
156
+ .filter(col => !col.primaryKey && col.name !== 'createTime' && col.name !== 'updateTime')
157
+ .map(col => ` ${col.name}: ''`)
158
+ .join(',\n')}
159
+ },
160
+ tableData: [],
161
+ dialogVisible: false,
162
+ isEdit: false,
163
+ currentRow: null,
164
+ loading: false,
165
+ pagination: {
166
+ current: 1,
167
+ size: 10,
168
+ total: 0
169
+ }
170
+ };
171
+ },
172
+ created() {
173
+ this.loadData();
174
+ },
175
+ methods: {
176
+ async loadData() {
177
+ this.loading = true;
178
+ try {
179
+ const { pageNum, pageSize } = { pageNum: this.pagination.current, pageSize: this.pagination.size };
180
+ const params = { ...this.searchForm, pageNum, pageSize };
181
+ const res = await ${entityLower}List(params);
182
+ this.tableData = res.list || [];
183
+ this.pagination.total = res.total || 0;
184
+ } catch (error) {
185
+ this.$message.error('Failed to load data');
186
+ console.error(error);
187
+ } finally {
188
+ this.loading = false;
189
+ }
190
+ },
191
+ handleSearch() {
192
+ this.pagination.current = 1;
193
+ this.loadData();
194
+ },
195
+ handleReset() {
196
+ ${columns
197
+ .filter(col => !col.primaryKey && col.name !== 'createTime' && col.name !== 'updateTime')
198
+ .map(col => ` this.searchForm.${col.name} = '';`)
199
+ .join('\n')}
200
+ this.handleSearch();
201
+ },
202
+ handleSizeChange(val) {
203
+ this.pagination.size = val;
204
+ this.loadData();
205
+ },
206
+ handleCurrentChange(val) {
207
+ this.pagination.current = val;
208
+ this.loadData();
209
+ },
210
+ handleAdd() {
211
+ this.isEdit = false;
212
+ this.currentRow = null;
213
+ this.dialogVisible = true;
214
+ },
215
+ handleEdit(row) {
216
+ this.isEdit = true;
217
+ this.currentRow = { ...row };
218
+ this.dialogVisible = true;
219
+ },
220
+ async handleDelete(row) {
221
+ try {
222
+ await this.$confirm('Confirm to delete this record?', 'Prompt', {
223
+ type: 'warning'
224
+ });
225
+ await ${entityLower}Delete(row.id);
226
+ this.$message.success('Deleted successfully');
227
+ this.loadData();
228
+ } catch (error) {
229
+ if (error !== 'cancel') {
230
+ this.$message.error('Delete failed');
231
+ console.error(error);
232
+ }
233
+ }
234
+ },
235
+ handleDialogSuccess() {
236
+ this.dialogVisible = false;
237
+ this.loadData();
238
+ }
239
+ }
240
+ };
241
+ </script>
242
+
243
+ <style scoped lang="scss">
244
+ .${entityLower}-page {
245
+ padding: 16px;
246
+ }
247
+ .search-card, .toolbar-card {
248
+ margin-bottom: 16px;
249
+ }
250
+ .pagination-wrapper {
251
+ margin-top: 16px;
252
+ text-align: right;
253
+ }
254
+ </style>
255
+ `;
256
+ }
257
+
258
+ /**
259
+ * Generate Vue2 Form Modal component
260
+ */
261
+ function generateVue2FormModal(entityName, columns) {
262
+ const entityLower = entityName.toLowerCase();
263
+ const entityCapital = capitalize(entityName);
264
+
265
+ const formItems = columns
266
+ .filter(col => !col.primaryKey)
267
+ .map(col => {
268
+ let input = `<el-input v-model="formData.${col.name}" placeholder="Please enter ${col.label}" />`;
269
+ if (col.type === 'Date' || col.type === 'DateTime') {
270
+ input = `<el-date-picker
271
+ v-model="formData.${col.name}"
272
+ type="date"
273
+ placeholder="Select ${col.label}"
274
+ value-format="yyyy-MM-dd"
275
+ />`;
276
+ } else if (col.type === 'Boolean' || col.type === 'boolean') {
277
+ input = `<el-switch v-model="formData.${col.name}" />`;
278
+ }
279
+ return ` <el-form-item label="${col.label}" prop="${col.name}"${col.required ? ' required' : ''}>
280
+ ${input}
281
+ </el-form-item>`;
282
+ })
283
+ .join('\n');
284
+
285
+ const initialData = columns
286
+ .filter(col => !col.primaryKey)
287
+ .map(col => ` ${col.name}: ${col.default ? JSON.stringify(col.default) : getDefaultValue(col.type)}`)
288
+ .join(',\n');
289
+
290
+ const rules = columns
291
+ .filter(col => col.required && !col.primaryKey)
292
+ .map(col => ` ${col.name}: [{ required: true, message: 'Please enter ${col.label}', trigger: 'blur' }]`)
293
+ .join(',\n');
294
+
295
+ const addEditMethod = `
296
+ async handleSubmit() {
297
+ this.$refs.form.validate(async valid => {
298
+ if (!valid) return;
299
+ try {
300
+ if (this.isEdit) {
301
+ await ${entityLower}Update(this.formData);
302
+ this.$message.success('Updated successfully');
303
+ } else {
304
+ await ${entityLower}Add(this.formData);
305
+ this.$message.success('Added successfully');
306
+ }
307
+ this.$emit('success');
308
+ this.resetForm();
309
+ } catch (error) {
310
+ this.$message.error(this.isEdit ? 'Update failed' : 'Add failed');
311
+ console.error(error);
312
+ }
313
+ });
314
+ }`;
315
+
316
+ return `<template>
317
+ <el-dialog
318
+ :title="dialogTitle"
319
+ :visible.sync="visible"
320
+ width="600px"
321
+ @close="resetForm">
322
+ <el-form ref="form" :model="formData" :rules="rules" label-width="100px">
323
+ ${formItems}
324
+ </el-form>
325
+ <span slot="footer" class="dialog-footer">
326
+ <el-button @click="visible = false">Cancel</el-button>
327
+ <el-button type="primary" @click="handleSubmit">Confirm</el-button>
328
+ </span>
329
+ </el-dialog>
330
+ </template>
331
+
332
+ <script>
333
+ import { ${entityLower}Add, ${entityLower}Update } from '@/api/${entityLower}';
334
+
335
+ function getDefaultValue(type) {
336
+ switch (type) {
337
+ case 'String': return '';
338
+ case 'Number': case 'Integer': case 'Long': return 0;
339
+ case 'Boolean': return false;
340
+ case 'Date': return '';
341
+ default: return '';
342
+ }
343
+ }
344
+
345
+ export default {
346
+ name: '${entityCapital}FormDialog',
347
+ props: {
348
+ visible: {
349
+ type: Boolean,
350
+ default: false
351
+ },
352
+ formData: {
353
+ type: Object,
354
+ default: null
355
+ },
356
+ isEdit: {
357
+ type: Boolean,
358
+ default: false
359
+ }
360
+ },
361
+ data() {
362
+ return {
363
+ formData: {
364
+ ${initialData}
365
+ },
366
+ rules: {
367
+ ${rules}
368
+ }
369
+ };
370
+ },
371
+ computed: {
372
+ dialogTitle() {
373
+ return this.isEdit ? 'Edit ${entityCapital}' : 'Add ${entityCapital}';
374
+ }
375
+ },
376
+ watch: {
377
+ formData(val) {
378
+ if (val && this.isEdit) {
379
+ this.formData = { ...val };
380
+ }
381
+ }
382
+ },
383
+ methods: {
384
+ resetForm() {
385
+ this.$refs.form && this.$refs.form.clearValidate();
386
+ ${initialData
387
+ .split('\n')
388
+ .map(line => ' this.formData.' + line.trim().split(':')[0] + ' = ' + line.trim().split('=')[1].trim())
389
+ .join('\n')}
390
+ },
391
+ ${addEditMethod.trim()}
392
+ }
393
+ };
394
+ </script>
395
+ `;
396
+ }
397
+
398
+ /**
399
+ * Generate Vue2 API module
400
+ */
401
+ function generateVue2Api(entityName, tableName) {
402
+ const entityLower = entityName.toLowerCase();
403
+ const entityCapital = capitalize(entityName);
404
+ const baseUrl = `/${tableName || entityLower}`;
405
+
406
+ return `import request from '@/utils/request';
407
+
408
+ /**
409
+ * ${entityCapital} API
410
+ */
411
+
412
+ // Get ${entityCapital} list with pagination
413
+ export function ${entityLower}List(params) {
414
+ return request({
415
+ url: '${baseUrl}/list',
416
+ method: 'get',
417
+ params
418
+ });
419
+ }
420
+
421
+ // Get ${entityCapital} by id
422
+ export function ${entityLower}GetById(id) {
423
+ return request({
424
+ url: '${baseUrl}/${id}',
425
+ method: 'get'
426
+ });
427
+ }
428
+
429
+ // Add ${entityCapital}
430
+ export function ${entityLower}Add(data) {
431
+ return request({
432
+ url: '${baseUrl}',
433
+ method: 'post',
434
+ data
435
+ });
436
+ }
437
+
438
+ // Update ${entityCapital}
439
+ export function ${entityLower}Update(data) {
440
+ return request({
441
+ url: '${baseUrl}',
442
+ method: 'put',
443
+ data
444
+ });
445
+ }
446
+
447
+ // Delete ${entityCapital}
448
+ export function ${entityLower}Delete(id) {
449
+ return request({
450
+ url: '${baseUrl}/${id}',
451
+ method: 'delete'
452
+ });
453
+ }
454
+ `;
455
+ }
456
+
457
+ // ========== SpringBoot + MyBatis Generation ==========
458
+
459
+ /**
460
+ * Generate MyBatis Entity class
461
+ */
462
+ function generateMyBatisEntity(entityName, columns, packageName = 'com.example.demo.entity') {
463
+ const fields = columns.map(col => {
464
+ return ` /**
465
+ * ${col.label || col.name}
466
+ */
467
+ private ${col.type} ${col.name};`;
468
+ }).join('\n\n');
469
+
470
+ return `package ${packageName};
471
+
472
+ import lombok.Data;
473
+ import java.io.Serializable;
474
+ ${columns.some(c => c.type === 'Date') ? 'import java.util.Date;' : ''}
475
+
476
+ /**
477
+ * ${entityName} Entity
478
+ */
479
+ @Data
480
+ public class ${entityName} implements Serializable {
481
+
482
+ private static final long serialVersionUID = 1L;
483
+
484
+ ${fields}
485
+ }
486
+ `;
487
+ }
488
+
489
+ /**
490
+ * Generate MyBatis Mapper interface
491
+ */
492
+ function generateMyBatisMapper(entityName, packageName = 'com.example.demo.mapper') {
493
+ const entityLower = entityName.toLowerCase();
494
+
495
+ return `package ${packageName};
496
+
497
+ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
498
+ import ${packageName.replace('.mapper', '.entity')}.${entityName};
499
+ import org.apache.ibatis.annotations.Mapper;
500
+
501
+ /**
502
+ * ${entityName} Mapper Interface
503
+ */
504
+ @Mapper
505
+ public interface ${entityName}Mapper extends BaseMapper<${entityName}> {
506
+
507
+ }
508
+ `;
509
+ }
510
+
511
+ /**
512
+ * Generate plain MyBatis Mapper interface (without MP)
513
+ */
514
+ function generatePlainMyBatisMapper(entityName, packageName = 'com.example.demo.mapper') {
515
+ const entityLower = entityName.toLowerCase();
516
+
517
+ return `package ${packageName};
518
+
519
+ import ${packageName.replace('.mapper', '.entity')}.${entityName};
520
+ import org.apache.ibatis.annotations.Mapper;
521
+ import org.apache.ibatis.annotations.Param;
522
+ import java.util.List;
523
+
524
+ /**
525
+ * ${entityName} Mapper Interface
526
+ */
527
+ @Mapper
528
+ public interface ${entityName}Mapper {
529
+
530
+ /**
531
+ * Query by primary key
532
+ */
533
+ ${entityName} selectById(Long id);
534
+
535
+ /**
536
+ * Query list by condition
537
+ */
538
+ List<${entityName}> selectList(@Param("query") ${entityName} query);
539
+
540
+ /**
541
+ * Count total
542
+ */
543
+ int count(@Param("query") ${entityName} query);
544
+
545
+ /**
546
+ * Insert
547
+ */
548
+ int insert(${entityName} record);
549
+
550
+ /**
551
+ * Update by primary key
552
+ */
553
+ int updateById(${entityName} record);
554
+
555
+ /**
556
+ * Delete by primary key
557
+ */
558
+ int deleteById(Long id);
559
+ }
560
+ `;
561
+ }
562
+
563
+ /**
564
+ * Generate SpringBoot Service interface
565
+ */
566
+ function generateSpringBootService(entityName, packageName = 'com.example.demo.service') {
567
+ const entityLower = entityName.toLowerCase();
568
+
569
+ return `package ${packageName};
570
+
571
+ import ${packageName.replace('.service', '.entity')}.${entityName};
572
+ import com.baomidou.mybatisplus.extension.service.IService;
573
+
574
+ /**
575
+ * ${entityName} Service Interface
576
+ */
577
+ public interface ${entityName}Service extends IService<${entityName}> {
578
+
579
+ }
580
+ `;
581
+ }
582
+
583
+ /**
584
+ * Generate plain Service interface (without MP)
585
+ */
586
+ function generatePlainSpringBootService(entityName, packageName = 'com.example.demo.service') {
587
+ const entityLower = entityName.toLowerCase();
588
+
589
+ return `package ${packageName};
590
+
591
+ import ${packageName.replace('.service', '.entity')}.${entityName};
592
+ import com.github.pagehelper.PageInfo;
593
+ import java.util.List;
594
+
595
+ /**
596
+ * ${entityName} Service Interface
597
+ */
598
+ public interface ${entityName}Service {
599
+
600
+ /**
601
+ * Get by ID
602
+ */
603
+ ${entityName} getById(Long id);
604
+
605
+ /**
606
+ * Query page
607
+ */
608
+ PageInfo<${entityName}> pageList(${entityName} query, int pageNum, int pageSize);
609
+
610
+ /**
611
+ * Create
612
+ */
613
+ int create(${entityName} record);
614
+
615
+ /**
616
+ * Update
617
+ */
618
+ int update(${entityName} record);
619
+
620
+ /**
621
+ * Delete
622
+ */
623
+ int delete(Long id);
624
+ }
625
+ `;
626
+ }
627
+
628
+ /**
629
+ * Generate Service Implementation
630
+ */
631
+ function generateSpringBootServiceImpl(entityName, packageName = 'com.example.demo.service.impl') {
632
+ const entityLower = entityName.toLowerCase();
633
+ const basePackage = packageName.replace('.service.impl', '');
634
+
635
+ return `package ${packageName};
636
+
637
+ import ${basePackage}.entity.${entityName};
638
+ import ${basePackage}.mapper.${entityName}Mapper;
639
+ import ${basePackage}.service.${entityName}Service;
640
+ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
641
+ import org.springframework.stereotype.Service;
642
+
643
+ /**
644
+ * ${entityName} Service Implementation
645
+ */
646
+ @Service
647
+ public class ${entityName}ServiceImpl extends ServiceImpl<${entityName}Mapper, ${entityName}> implements ${entityName}Service {
648
+
649
+ }
650
+ `;
651
+ }
652
+
653
+ /**
654
+ * Generate plain Service Implementation
655
+ */
656
+ function generatePlainSpringBootServiceImpl(entityName, packageName = 'com.example.demo.service.impl') {
657
+ const entityLower = entityName.toLowerCase();
658
+ const basePackage = packageName.replace('.service.impl', '');
659
+
660
+ return `package ${packageName};
661
+
662
+ import ${basePackage}.entity.${entityName};
663
+ import ${basePackage}.mapper.${entityName}Mapper;
664
+ import ${basePackage}.service.${entityName}Service;
665
+ import com.github.pagehelper.PageHelper;
666
+ import com.github.pagehelper.PageInfo;
667
+ import org.springframework.beans.factory.annotation.Autowired;
668
+ import org.springframework.stereotype.Service;
669
+
670
+ import java.util.List;
671
+
672
+ /**
673
+ * ${entityName} Service Implementation
674
+ */
675
+ @Service
676
+ public class ${entityName}ServiceImpl implements ${entityName}Service {
677
+
678
+ @Autowired
679
+ private ${entityName}Mapper ${entityLower}Mapper;
680
+
681
+ @Override
682
+ public ${entityName} getById(Long id) {
683
+ return ${entityLower}Mapper.selectById(id);
684
+ }
685
+
686
+ @Override
687
+ public PageInfo<${entityName}> pageList(${entityName} query, int pageNum, int pageSize) {
688
+ PageHelper.startPage(pageNum, pageSize);
689
+ List<${entityName}> list = ${entityLower}Mapper.selectList(query);
690
+ return new PageInfo<>(list);
691
+ }
692
+
693
+ @Override
694
+ public int create(${entityName} record) {
695
+ return ${entityLower}Mapper.insert(record);
696
+ }
697
+
698
+ @Override
699
+ public int update(${entityName} record) {
700
+ return ${entityLower}Mapper.updateById(record);
701
+ }
702
+
703
+ @Override
704
+ public int delete(Long id) {
705
+ return ${entityLower}Mapper.deleteById(id);
706
+ }
707
+ }
708
+ `;
709
+ }
710
+
711
+ /**
712
+ * Generate SpringBoot Controller
713
+ */
714
+ function generateSpringBootController(entityName, packageName = 'com.example.demo.controller') {
715
+ const entityLower = entityName.toLowerCase();
716
+ const basePackage = packageName.replace('.controller', '');
717
+ const basePath = `/${entityLower}`;
718
+
719
+ return `package ${packageName};
720
+
721
+ import ${basePackage}.entity.${entityName};
722
+ import ${basePackage}.service.${entityName}Service;
723
+ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
724
+ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
725
+ import com.baomidou.mybatisplus.core.metadata.IPage;
726
+ import org.springframework.beans.factory.annotation.Autowired;
727
+ import org.springframework.web.bind.annotation.*;
728
+ import io.swagger.annotations.Api;
729
+ import io.swagger.annotations.ApiOperation;
730
+ import com.common.result.Result;
731
+
732
+ /**
733
+ * ${entityName} Controller
734
+ */
735
+ @Api(tags = "${entityName} Controller")
736
+ @RestController
737
+ @RequestMapping("${basePath}")
738
+ public class ${entityName}Controller {
739
+
740
+ @Autowired
741
+ private ${entityName}Service ${entityLower}Service;
742
+
743
+ @ApiOperation("Get ${entityName} page list")
744
+ @GetMapping("/list")
745
+ public Result<IPage<${entityName}>> list(
746
+ @RequestParam(defaultValue = "1") Integer pageNum,
747
+ @RequestParam(defaultValue = "10") Integer pageSize,
748
+ ${entityName} query) {
749
+ Page<${entityName}> page = new Page<>(pageNum, pageSize);
750
+ LambdaQueryWrapper<${entityName}> wrapper = new LambdaQueryWrapper<>();
751
+ // TODO: Add query conditions
752
+ IPage<${entityName}> result = ${entityLower}Service.page(page, wrapper);
753
+ return Result.success(result);
754
+ }
755
+
756
+ @ApiOperation("Get ${entityName} detail by ID")
757
+ @GetMapping("/{id}")
758
+ public Result<${entityName}> getById(@PathVariable Long id) {
759
+ ${entityName} ${entityLower} = ${entityLower}Service.getById(id);
760
+ return Result.success(${entityLower});
761
+ }
762
+
763
+ @ApiOperation("Create ${entityName}")
764
+ @PostMapping
765
+ public Result<Boolean> create(@RequestBody ${entityName} record) {
766
+ boolean result = ${entityLower}Service.save(record);
767
+ return Result.success(result);
768
+ }
769
+
770
+ @ApiOperation("Update ${entityName}")
771
+ @PutMapping
772
+ public Result<Boolean> update(@RequestBody ${entityName} record) {
773
+ boolean result = ${entityLower}Service.updateById(record);
774
+ return Result.success(result);
775
+ }
776
+
777
+ @ApiOperation("Delete ${entityName}")
778
+ @DeleteMapping("/{id}")
779
+ public Result<Boolean> delete(@PathVariable Long id) {
780
+ boolean result = ${entityLower}Service.removeById(id);
781
+ return Result.success(result);
782
+ }
783
+ }
784
+ `;
785
+ }
786
+
787
+ /**
788
+ * Generate plain Controller (without MP)
789
+ */
790
+ function generatePlainSpringBootController(entityName, packageName = 'com.example.demo.controller') {
791
+ const entityLower = entityName.toLowerCase();
792
+ const basePackage = packageName.replace('.controller', '');
793
+ const basePath = `/${entityLower}`;
794
+
795
+ return `package ${packageName};
796
+
797
+ import ${basePackage}.entity.${entityName};
798
+ import ${basePackage}.service.${entityName}Service;
799
+ import com.github.pagehelper.PageInfo;
800
+ import org.springframework.beans.factory.annotation.Autowired;
801
+ import org.springframework.web.bind.annotation.*;
802
+ import io.swagger.annotations.Api;
803
+ import io.swagger.annotations.ApiOperation;
804
+ import com.common.result.Result;
805
+
806
+ /**
807
+ * ${entityName} Controller
808
+ */
809
+ @Api(tags = "${entityName} Controller")
810
+ @RestController
811
+ @RequestMapping("${basePath}")
812
+ public class ${entityName}Controller {
813
+
814
+ @Autowired
815
+ private ${entityName}Service ${entityLower}Service;
816
+
817
+ @ApiOperation("Get ${entityName} page list")
818
+ @GetMapping("/list")
819
+ public Result<PageInfo<${entityName}>> list(
820
+ @RequestParam(defaultValue = "1") Integer pageNum,
821
+ @RequestParam(defaultValue = "10") Integer pageSize,
822
+ ${entityName} query) {
823
+ PageInfo<${entityName}> result = ${entityLower}Service.pageList(query, pageNum, pageSize);
824
+ return Result.success(result);
825
+ }
826
+
827
+ @ApiOperation("Get ${entityName} detail by ID")
828
+ @GetMapping("/{id}")
829
+ public Result<${entityName}> getById(@PathVariable Long id) {
830
+ ${entityName} ${entityLower} = ${entityLower}Service.getById(id);
831
+ return Result.success(${entityLower});
832
+ }
833
+
834
+ @ApiOperation("Create ${entityName}")
835
+ @PostMapping
836
+ public Result<Integer> create(@RequestBody ${entityName} record) {
837
+ int result = ${entityLower}Service.create(record);
838
+ return Result.success(result);
839
+ }
840
+
841
+ @ApiOperation("Update ${entityName}")
842
+ @PutMapping
843
+ public Result<Integer> update(@RequestBody ${entityName} record) {
844
+ int result = ${entityLower}Service.update(record);
845
+ return Result.success(result);
846
+ }
847
+
848
+ @ApiOperation("Delete ${entityName}")
849
+ @DeleteMapping("/{id}")
850
+ public Result<Integer> delete(@PathVariable Long id) {
851
+ int result = ${entityLower}Service.delete(id);
852
+ return Result.success(result);
853
+ }
854
+ }
855
+ `;
856
+ }
857
+
858
+ /**
859
+ * Generate MyBatis XML Mapper
860
+ */
861
+ function generateMyBatisXml(entityName, tableName, columns) {
862
+ const table = tableName || camelToSnake(entityName);
863
+ const primaryKey = columns.find(c => c.primaryKey) || columns[0];
864
+
865
+ const resultMap = ` <resultMap id="BaseResultMap" type="${entityName}">
866
+ ${columns.map(col => ` <${col.primaryKey ? 'id' : 'result'} column="${camelToSnake(col.name)}" property="${col.name}" jdbcType="${getJdbcType(col.type)}" />`).join('\n')}
867
+ </resultMap>`;
868
+
869
+ const baseColumnList = columns.map(col => camelToSnake(col.name)).join(',\n ');
870
+
871
+ const insertColumns = columns.map(col => camelToSnake(col.name)).join(',\n ');
872
+ const insertValues = columns.map(col => `#{${col.name}}`).join(',\n ');
873
+
874
+ const dynamicSet = columns
875
+ .filter(col => !col.primaryKey)
876
+ .map(col => ` <if test="${col.name} != null">
877
+ ${camelToSnake(col.name)} = #{${col.name}},
878
+ </if>`)
879
+ .join('\n');
880
+
881
+ const dynamicWhere = columns
882
+ .filter(col => !col.primaryKey)
883
+ .map(col => ` <if test="query.${col.name} != null and query.${col.name} != ''">
884
+ AND ${camelToSnake(col.name)} = #{query.${col.name}}
885
+ </if>`)
886
+ .join('\n');
887
+
888
+ return `<?xml version="1.0" encoding="UTF-8"?>
889
+ <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
890
+ <mapper namespace="com.example.demo.mapper.${entityName}Mapper">
891
+
892
+ ${resultMap}
893
+
894
+ <sql id="Base_Column_List">
895
+ ${baseColumnList}
896
+ </sql>
897
+
898
+ <select id="selectById" resultMap="BaseResultMap">
899
+ SELECT
900
+ <include refid="Base_Column_List" />
901
+ FROM ${table}
902
+ WHERE ${camelToSnake(primaryKey.name)} = #{id}
903
+ </select>
904
+
905
+ <select id="selectList" resultMap="BaseResultMap">
906
+ SELECT
907
+ <include refid="Base_Column_List" />
908
+ FROM ${table}
909
+ <where>
910
+ ${dynamicWhere}
911
+ </where>
912
+ ORDER BY ${camelToSnake(primaryKey.name)} DESC
913
+ </select>
914
+
915
+ <select id="count" resultType="int">
916
+ SELECT COUNT(*)
917
+ FROM ${table}
918
+ <where>
919
+ ${dynamicWhere}
920
+ </where>
921
+ </select>
922
+
923
+ <insert id="insert" parameterType="${entityName}">
924
+ INSERT INTO ${table} (
925
+ ${insertColumns}
926
+ ) VALUES (
927
+ ${insertValues}
928
+ );
929
+ </insert>
930
+
931
+ <update id="updateById" parameterType="${entityName}">
932
+ UPDATE ${table}
933
+ <set>
934
+ ${dynamicSet}
935
+ </set>
936
+ WHERE ${camelToSnake(primaryKey.name)} = #{${primaryKey.name}}
937
+ </update>
938
+
939
+ <delete id="deleteById">
940
+ DELETE FROM ${table}
941
+ WHERE ${camelToSnake(primaryKey.name)} = #{id}
942
+ </delete>
943
+ </mapper>
944
+ `;
945
+ }
946
+
947
+ /**
948
+ * Get JDBC type from Java type
949
+ */
950
+ function getJdbcType(javaType) {
951
+ const map = {
952
+ 'String': 'VARCHAR',
953
+ 'Long': 'BIGINT',
954
+ 'Integer': 'INTEGER',
955
+ 'int': 'INTEGER',
956
+ 'Boolean': 'BOOLEAN',
957
+ 'Date': 'TIMESTAMP',
958
+ 'DateTime': 'TIMESTAMP',
959
+ 'BigDecimal': 'DECIMAL',
960
+ 'Double': 'DOUBLE',
961
+ 'Float': 'FLOAT'
962
+ };
963
+ return map[javaType] || 'VARCHAR';
964
+ }
965
+
966
+ /**
967
+ * Get default value for Vue data
968
+ */
969
+ function getDefaultValue(type) {
970
+ switch (type) {
971
+ case 'String': case 'Date': return "''";
972
+ case 'Number': case 'Integer': case 'Long': return '0';
973
+ case 'Boolean': return 'false';
974
+ default: return "''";
975
+ }
976
+ }
977
+
978
+ /**
979
+ * Generate full-stack CRUD
980
+ */
981
+ function generateFullStackCrud(entityName, tableName, columns, options = {}) {
982
+ const { useMyBatisPlus = true, basePackage = 'com.example.demo' } = options;
983
+
984
+ return {
985
+ vue: {
986
+ crudPage: generateVue2CrudPage(entityName, tableName, columns),
987
+ formDialog: generateVue2FormModal(entityName, columns),
988
+ api: generateVue2Api(entityName, tableName)
989
+ },
990
+ springboot: {
991
+ entity: generateMyBatisEntity(entityName, columns, `${basePackage}.entity`),
992
+ mapper: useMyBatisPlus
993
+ ? generateMyBatisMapper(entityName, `${basePackage}.mapper`)
994
+ : generatePlainMyBatisMapper(entityName, `${basePackage}.mapper`),
995
+ service: useMyBatisPlus
996
+ ? generateSpringBootService(entityName, `${basePackage}.service`)
997
+ : generatePlainSpringBootService(entityName, `${basePackage}.service`),
998
+ serviceImpl: useMyBatisPlus
999
+ ? generateSpringBootServiceImpl(entityName, `${basePackage}.service.impl`)
1000
+ : generatePlainSpringBootServiceImpl(entityName, `${basePackage}.service.impl`),
1001
+ controller: useMyBatisPlus
1002
+ ? generateSpringBootController(entityName, `${basePackage}.controller`)
1003
+ : generatePlainSpringBootController(entityName, `${basePackage}.controller`)
1004
+ },
1005
+ mybatis: {
1006
+ xml: useMyBatisPlus ? null : generateMyBatisXml(entityName, tableName, columns)
1007
+ }
1008
+ };
1009
+ }
1010
+
1011
+ // ========== Export ==========
1012
+
1013
+ module.exports = {
1014
+ getInfo,
1015
+ // Vue2
1016
+ generateVue2Component,
1017
+ generateVue2CrudPage,
1018
+ generateVue2FormModal,
1019
+ generateVue2Api,
1020
+ // MyBatis
1021
+ generateMyBatisEntity,
1022
+ generateMyBatisMapper,
1023
+ generatePlainMyBatisMapper,
1024
+ generateMyBatisXml,
1025
+ // SpringBoot
1026
+ generateSpringBootService,
1027
+ generatePlainSpringBootService,
1028
+ generateSpringBootServiceImpl,
1029
+ generatePlainSpringBootServiceImpl,
1030
+ generateSpringBootController,
1031
+ generatePlainSpringBootController,
1032
+ // Full Stack
1033
+ generateFullStackCrud
1034
+ };
1035
+
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@skills-cli/vue2-springboot-mybatis",
3
+ "version": "1.0.0",
4
+ "description": "Universal coding assistance skills for Vue2 + SpringBoot + MyBatis full-stack development",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [
10
+ "skills-cli",
11
+ "vue2",
12
+ "springboot",
13
+ "mybatis",
14
+ "code-generation",
15
+ "crud",
16
+ "fullstack",
17
+ "coding-assistance"
18
+ ],
19
+ "author": "skills-cli",
20
+ "license": "MIT",
21
+ "tags": [
22
+ "vue2",
23
+ "springboot",
24
+ "mybatis",
25
+ "code-generation",
26
+ "crud",
27
+ "fullstack"
28
+ ],
29
+ "capabilities": [
30
+ "vue2-component",
31
+ "vue2-crud",
32
+ "springboot-controller",
33
+ "springboot-service",
34
+ "mybatis-entity",
35
+ "mybatis-mapper",
36
+ "crud-generation",
37
+ "code-template"
38
+ ]
39
+ }
package/skills.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "vue2-springboot-mybatis",
3
+ "version": "1.0.0",
4
+ "description": "Universal coding assistance skills for Vue2 + SpringBoot + MyBatis full-stack development",
5
+ "priority": 80,
6
+ "tags": ["vue2", "springboot", "mybatis", "code-generation", "crud", "fullstack", "coding-assistance"],
7
+ "capabilities": [
8
+ "generate-vue2-component",
9
+ "generate-vue2-crud-page",
10
+ "generate-springboot-controller",
11
+ "generate-springboot-service",
12
+ "generate-mybatis-entity",
13
+ "generate-mybatis-mapper",
14
+ "generate-mybatis-xml",
15
+ "generate-crud-fullstack",
16
+ "code-templates"
17
+ ],
18
+ "dependencies": {},
19
+ "devDependencies": {},
20
+ "priorityOverrides": {},
21
+ "config": {
22
+ "vue2": {
23
+ "componentPath": "src/components",
24
+ "viewPath": "src/views",
25
+ "apiPath": "src/api"
26
+ },
27
+ "springboot": {
28
+ "basePackage": "com.example.demo",
29
+ "entityPath": "src/main/java/**/entity",
30
+ "mapperPath": "src/main/java/**/mapper",
31
+ "servicePath": "src/main/java/**/service",
32
+ "controllerPath": "src/main/java/**/controller",
33
+ "xmlPath": "src/main/resources/mapper"
34
+ }
35
+ }
36
+ }