diff --git a/build.gradle b/build.gradle index c9c4843..9f5c81b 100644 --- a/build.gradle +++ b/build.gradle @@ -28,11 +28,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' compile group: 'mysql', name: 'mysql-connector-java', version: '8.0.16' - compileOnly 'org.projectlombok:lombok' - annotationProcessor 'org.projectlombok:lombok' compile group: 'com.googlecode.plist', name: 'dd-plist', version: '1.21' compile group: 'net.dongliu', name: 'apk-parser', version: '2.6.9' - compile group: 'net.glxn.qrgen', name: 'javase', version: '2.0' + compile group: 'com.google.zxing', name: 'javase', version: '3.4.0' compile group: 'commons-io', name: 'commons-io', version: '2.6' compile group: 'com.jcraft', name: 'jzlib', version: '1.1.3' compile group: 'org.freemarker', name: 'freemarker', version: '2.3.28' diff --git a/src/main/java/org/yzr/controller/PackageController.java b/src/main/java/org/yzr/controller/PackageController.java index 5343b79..c26aeb5 100644 --- a/src/main/java/org/yzr/controller/PackageController.java +++ b/src/main/java/org/yzr/controller/PackageController.java @@ -2,7 +2,6 @@ package org.yzr.controller; import com.alibaba.fastjson.JSON; -import net.glxn.qrgen.javase.QRCode; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.springframework.stereotype.Controller; @@ -14,6 +13,7 @@ import org.yzr.model.Package; import org.yzr.service.AppService; import org.yzr.service.PackageService; import org.yzr.utils.PathManager; +import org.yzr.utils.QRCodeUtil; import org.yzr.utils.ipa.PlistGenerator; import org.yzr.utils.webhook.WebHookClient; import org.yzr.vo.AppViewModel; @@ -165,7 +165,7 @@ public class PackageController { public void getManifest(@PathVariable("id") String id, HttpServletResponse response) { try { PackageViewModel viewModel = this.packageService.findById(id); - if (viewModel != null && viewModel.isIOS()) { + if (viewModel != null && viewModel.isiOS()) { response.setContentType("application/force-download"); response.setHeader("Content-Disposition", "attachment;fileName=manifest.plist"); Writer writer = new OutputStreamWriter(response.getOutputStream()); @@ -187,7 +187,7 @@ public class PackageController { PackageViewModel viewModel = this.packageService.findById(id); if (viewModel != null) { response.setContentType("image/png"); - QRCode.from(viewModel.getPreviewURL()).withSize(250, 250).writeTo(response.getOutputStream()); + QRCodeUtil.encode(viewModel.getPreviewURL()).withSize(250, 250).writeTo(response.getOutputStream()); } } catch (Exception e) { e.printStackTrace(); diff --git a/src/main/java/org/yzr/model/App.java b/src/main/java/org/yzr/model/App.java index bb06cdf..2a62a24 100644 --- a/src/main/java/org/yzr/model/App.java +++ b/src/main/java/org/yzr/model/App.java @@ -1,8 +1,6 @@ package org.yzr.model; -import lombok.Getter; -import lombok.Setter; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; @@ -10,8 +8,6 @@ import java.util.List; @Entity @Table(name = "tb_app", uniqueConstraints = {@UniqueConstraint(columnNames={"platform", "bundleID"})}) -@Setter -@Getter public class App { // 主键 @Id @@ -43,4 +39,83 @@ public class App { @JoinColumn(name = "currentID",referencedColumnName = "id") private Package currentPackage; + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getBundleID() { + return bundleID; + } + + public void setBundleID(String bundleID) { + this.bundleID = bundleID; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getShortCode() { + return shortCode; + } + + public void setShortCode(String shortCode) { + this.shortCode = shortCode; + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public List getPackageList() { + return packageList; + } + + public void setPackageList(List packageList) { + this.packageList = packageList; + } + + public List getWebHookList() { + return webHookList; + } + + public void setWebHookList(List webHookList) { + this.webHookList = webHookList; + } + + public Package getCurrentPackage() { + return currentPackage; + } + + public void setCurrentPackage(Package currentPackage) { + this.currentPackage = currentPackage; + } } diff --git a/src/main/java/org/yzr/model/Package.java b/src/main/java/org/yzr/model/Package.java index 8b49716..45591c0 100644 --- a/src/main/java/org/yzr/model/Package.java +++ b/src/main/java/org/yzr/model/Package.java @@ -1,16 +1,12 @@ package org.yzr.model; -import lombok.Getter; -import lombok.Setter; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; @Entity @Table(name="tb_package") -@Setter -@Getter public class Package { // 主键 @Id @@ -46,4 +42,107 @@ public class Package { @JoinColumn(name = "provisionId",referencedColumnName = "id") private Provision provision; + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getBundleID() { + return bundleID; + } + + public void setBundleID(String bundleID) { + this.bundleID = bundleID; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getBuildVersion() { + return buildVersion; + } + + public void setBuildVersion(String buildVersion) { + this.buildVersion = buildVersion; + } + + public long getCreateTime() { + return createTime; + } + + public void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public String getMinVersion() { + return minVersion; + } + + public void setMinVersion(String minVersion) { + this.minVersion = minVersion; + } + + public String getPlatform() { + return platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + public String getExtra() { + return extra; + } + + public void setExtra(String extra) { + this.extra = extra; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public App getApp() { + return app; + } + + public void setApp(App app) { + this.app = app; + } + + public Provision getProvision() { + return provision; + } + + public void setProvision(Provision provision) { + this.provision = provision; + } } diff --git a/src/main/java/org/yzr/model/Provision.java b/src/main/java/org/yzr/model/Provision.java index fc9cfe8..95f3c11 100644 --- a/src/main/java/org/yzr/model/Provision.java +++ b/src/main/java/org/yzr/model/Provision.java @@ -1,7 +1,5 @@ package org.yzr.model; -import lombok.Getter; -import lombok.Setter; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; @@ -10,8 +8,6 @@ import java.util.Date; @Entity @Table(name="tb_provision") -@Setter -@Getter public class Provision { // 主键 @Id @@ -29,4 +25,84 @@ public class Provision { private int deviceCount; private String type; private boolean isEnterprise; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getTeamName() { + return teamName; + } + + public void setTeamName(String teamName) { + this.teamName = teamName; + } + + public String getTeamID() { + return teamID; + } + + public void setTeamID(String teamID) { + this.teamID = teamID; + } + + public Date getCreateDate() { + return createDate; + } + + public void setCreateDate(Date createDate) { + this.createDate = createDate; + } + + public Date getExpirationDate() { + return expirationDate; + } + + public void setExpirationDate(Date expirationDate) { + this.expirationDate = expirationDate; + } + + public String getUUID() { + return UUID; + } + + public void setUUID(String UUID) { + this.UUID = UUID; + } + + public String[] getDevices() { + return devices; + } + + public void setDevices(String[] devices) { + this.devices = devices; + } + + public int getDeviceCount() { + return deviceCount; + } + + public void setDeviceCount(int deviceCount) { + this.deviceCount = deviceCount; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public boolean isEnterprise() { + return isEnterprise; + } + + public void setEnterprise(boolean enterprise) { + isEnterprise = enterprise; + } } diff --git a/src/main/java/org/yzr/model/WebHook.java b/src/main/java/org/yzr/model/WebHook.java index 11f7e1e..04b09b5 100644 --- a/src/main/java/org/yzr/model/WebHook.java +++ b/src/main/java/org/yzr/model/WebHook.java @@ -1,16 +1,12 @@ package org.yzr.model; -import lombok.Getter; -import lombok.Setter; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; @Entity @Table(name = "tb_web_hook") -@Setter -@Getter public class WebHook { // 钉钉 public static final String WEB_HOOK_TYPE_DING_DING="DingDing"; @@ -31,4 +27,44 @@ public class WebHook { @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.LAZY) @JoinColumn(name="appId") private App app; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public App getApp() { + return app; + } + + public void setApp(App app) { + this.app = app; + } } diff --git a/src/main/java/org/yzr/service/PackageService.java b/src/main/java/org/yzr/service/PackageService.java index ef50da6..af2a1c3 100644 --- a/src/main/java/org/yzr/service/PackageService.java +++ b/src/main/java/org/yzr/service/PackageService.java @@ -1,22 +1,17 @@ package org.yzr.service; -import lombok.SneakyThrows; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.springframework.stereotype.Service; -import org.yzr.dao.AppDao; import org.yzr.dao.PackageDao; -import org.yzr.model.App; import org.yzr.model.Package; import org.yzr.utils.ImageUtils; import org.yzr.utils.PathManager; -import org.yzr.utils.ipa.PlistGenerator; import org.yzr.utils.parser.ParserClient; import org.yzr.vo.PackageViewModel; import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; import javax.transaction.Transactional; import java.io.File; @@ -39,12 +34,9 @@ public class PackageService { String tempIconPath = PathManager.getTempIconPath(aPackage); String iconPath = packagePath + File.separator + "icon.png"; String sourcePath = packagePath + File.separator + fileName; - String jpgIconPath = packagePath + File.separator + "icon.jpg"; // 拷贝图标 ImageUtils.resize(tempIconPath, iconPath, 192, 192); - // 生成钉钉发送所需要图片 - ImageUtils.convertPNGToJPG(iconPath, jpgIconPath, 64, 64); // 源文件 FileUtils.copyFile(new File(filePath), new File(sourcePath)); diff --git a/src/main/java/org/yzr/utils/QRCodeUtil.java b/src/main/java/org/yzr/utils/QRCodeUtil.java new file mode 100644 index 0000000..ac7f767 --- /dev/null +++ b/src/main/java/org/yzr/utils/QRCodeUtil.java @@ -0,0 +1,204 @@ +package org.yzr.utils; + +import com.google.zxing.*; +import com.google.zxing.client.j2se.BufferedImageLuminanceSource; +import com.google.zxing.client.j2se.MatrixToImageConfig; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.common.HybridBinarizer; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +public class QRCodeUtil { + + private String text; + + private Integer width = 200; + + private Integer height = 200; + + private static final float PERCENT = 0.2F; + + private static final int CORNER_RADIUS = 5; + + private File icon; + + private String format = "png"; + + public static QRCodeUtil encode(String text) { + QRCodeUtil util = new QRCodeUtil(); + util.text = text; + return util; + } + + public QRCodeUtil withSize(Integer width, Integer height) { + this.width = width; + this.height = height; + return this; + } + + public QRCodeUtil withIcon(File icon) { + this.icon = icon; + return this; + } + + public boolean writeTo(OutputStream outputStream) { + try { + BitMatrix bitMatrix = getBitMatrix(); + if (this.icon != null) { + MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF); + BufferedImage bufferedImage = drawIconInMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), this.icon); + ImageIO.write(bufferedImage, format, outputStream); + } else { + MatrixToImageWriter.writeToStream(bitMatrix, format, outputStream); + } + return true; + } catch (WriterException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + public boolean writeTo(File file) { + try { + BitMatrix bitMatrix = getBitMatrix(); + if (this.icon != null) { + MatrixToImageConfig matrixToImageConfig = new MatrixToImageConfig(0xFF000001, 0xFFFFFFFF); + BufferedImage bufferedImage = drawIconInMatrix(MatrixToImageWriter.toBufferedImage(bitMatrix,matrixToImageConfig), this.icon); + ImageIO.write(bufferedImage, format, file); + } else { + MatrixToImageWriter.writeToPath(bitMatrix, format, file.toPath()); + } + return true; + } catch (WriterException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + private BitMatrix getBitMatrix() throws WriterException { + Map hints = new HashMap<>(); + //内容编码格式 + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); + // 指定纠错等级 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); + //设置二维码边的空度,非负数 + hints.put(EncodeHintType.MARGIN, 1); + return new MultiFormatWriter().encode(this.text, BarcodeFormat.QR_CODE, width, height, hints); + } + + + /** + * 识别指定文件的二维码 + * @param file + * @return + */ + public static String parseCode(File file) { + BufferedImage bufferedImage = null; + try { + bufferedImage = ImageIO.read(file); + } catch (IOException e) { + e.printStackTrace(); + } + return parseCode(bufferedImage); + } + + /** + * 识别指定图片的二维码 + * @param bufferedImage + * @return + */ + public static String parseCode(BufferedImage bufferedImage) { + String content = null; + try { + //读取指定的二维码文件 + MultiFormatReader formatReader = new MultiFormatReader(); + BinaryBitmap binaryBitmap= new BinaryBitmap(new HybridBinarizer(new BufferedImageLuminanceSource(bufferedImage))); + //定义二维码参数 + Map hints= new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); + Result result = formatReader.decode(binaryBitmap, hints); + //输出相关的二维码信息 + System.out.println("解析结果:"+result.toString()); + System.out.println("二维码格式类型:"+result.getBarcodeFormat()); + System.out.println("二维码文本内容:"+result.getText()); + content = result.getText(); + if (bufferedImage != null) { + bufferedImage.flush(); + } + } catch (NotFoundException e) { + e.printStackTrace(); + } + return content; + } + + /** + * 识别输入流的二维码 + * @param inputStream + * @return + */ + public static String parseCode(InputStream inputStream) { + BufferedImage bufferedImage = null; + try { + bufferedImage = ImageIO.read(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } + return parseCode(bufferedImage); + } + + /** + * 二维码添加logo + * @param matrixImage 源二维码图片 + * @param logoFile logo图片 + * @return 返回带有logo的二维码图片 + */ + private BufferedImage drawIconInMatrix(BufferedImage matrixImage, File logoFile) throws IOException{ + /** + * 读取二维码图片,并构建绘图对象 + */ + Graphics2D g2 = matrixImage.createGraphics(); + int matrixWidth = matrixImage.getWidth(); + int matrixHeight = matrixImage.getHeight(); + + /** + * 读取Logo图片 + */ + BufferedImage logo = ImageIO.read(logoFile); + + //开始绘制图片 + g2.drawImage(logo,(int)(matrixWidth * PERCENT*2),(int)(matrixHeight * PERCENT*2), (int)(matrixWidth * PERCENT), (int)(matrixHeight * PERCENT), null);//绘制 + BasicStroke stroke = new BasicStroke(5,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND); + g2.setStroke(stroke);// 设置笔画对象 + //指定弧度的圆角矩形 + RoundRectangle2D.Float round = new RoundRectangle2D.Float(matrixWidth * PERCENT*2, matrixHeight * PERCENT*2, matrixWidth * PERCENT, matrixHeight * PERCENT,CORNER_RADIUS,CORNER_RADIUS); + g2.setColor(Color.white); + g2.draw(round);// 绘制圆弧矩形 + + //设置logo 有一道灰色边框 + BasicStroke stroke2 = new BasicStroke(1,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND); + g2.setStroke(stroke2);// 设置笔画对象 + RoundRectangle2D.Float round2 = new RoundRectangle2D.Float(matrixWidth * PERCENT*2+2, matrixHeight * PERCENT*2+2, matrixWidth * PERCENT-4, matrixHeight * PERCENT-4,CORNER_RADIUS,CORNER_RADIUS); + g2.setColor(new Color(128,128,128)); + g2.draw(round2);// 绘制圆弧矩形 + + g2.dispose(); + matrixImage.flush() ; + return matrixImage ; + } +} + diff --git a/src/main/java/org/yzr/utils/webhook/DingDingWebHook.java b/src/main/java/org/yzr/utils/webhook/DingDingWebHook.java index f43ba47..3c17c0f 100644 --- a/src/main/java/org/yzr/utils/webhook/DingDingWebHook.java +++ b/src/main/java/org/yzr/utils/webhook/DingDingWebHook.java @@ -9,7 +9,9 @@ import org.yzr.model.Package; import org.yzr.model.WebHook; import org.yzr.utils.ImageUtils; import org.yzr.utils.PathManager; +import org.yzr.utils.QRCodeUtil; +import java.io.File; import java.util.HashMap; import java.util.Map; @@ -56,9 +58,16 @@ public class DingDingWebHook implements IWebHook { } String appInfo = String.format("[%s(%s)更新](%s)", app.getName(), platform, url); + + String iconPath = PathManager.getFullPath(app.getCurrentPackage()) + "icon.png"; // 将图片转为 base64, 内网 ip 钉钉无法访问,直接给图片数据 - String iconPath = PathManager.getFullPath(app.getCurrentPackage()) + "icon.jpg"; - String icon = "data:image/jpg;base64," + ImageUtils.convertImageToBase64(iconPath); + String codePath = PathManager.getFullPath(app.getCurrentPackage()) + "code.jpg"; + File codeFile = new File(codePath); + // 图片不存在,生成图片 + if (!codeFile.exists()) { + QRCodeUtil.encode(url).withSize(150, 150).withIcon(new File(iconPath)).writeTo(new File(codePath)); + } + String icon = "data:image/jpg;base64," + ImageUtils.convertImageToBase64(codePath); String pathInfo = String.format("![%s](%s)", app.getName(), icon); String otherInfo = String.format("链接:[%s](%s) \n\n 版本:%s (Build: %s)", url, url, app.getCurrentPackage().getVersion(), app.getCurrentPackage().getBuildVersion()); String message = this.getPackageMessage(app.getCurrentPackage()); diff --git a/src/main/java/org/yzr/vo/AppViewModel.java b/src/main/java/org/yzr/vo/AppViewModel.java index 1668b95..9e1f08d 100644 --- a/src/main/java/org/yzr/vo/AppViewModel.java +++ b/src/main/java/org/yzr/vo/AppViewModel.java @@ -1,18 +1,13 @@ package org.yzr.vo; -import lombok.Data; -import lombok.Getter; -import lombok.Setter; import org.yzr.model.App; import org.yzr.model.Package; import org.yzr.utils.PathManager; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; -@Getter public class AppViewModel { private String id; @@ -106,4 +101,52 @@ public class AppViewModel { }); return packageViewModels; } + + public String getId() { + return id; + } + + public String getName() { + return name; + } + + public String getPlatform() { + return platform; + } + + public String getBundleID() { + return bundleID; + } + + public String getIcon() { + return icon; + } + + public String getVersion() { + return version; + } + + public String getBuildVersion() { + return buildVersion; + } + + public String getMinVersion() { + return minVersion; + } + + public String getShortCode() { + return shortCode; + } + + public String getInstallPath() { + return installPath; + } + + public List getPackageList() { + return packageList; + } + + public PackageViewModel getCurrentPackage() { + return currentPackage; + } } diff --git a/src/main/java/org/yzr/vo/PackageViewModel.java b/src/main/java/org/yzr/vo/PackageViewModel.java index 340a6b9..b806a9a 100644 --- a/src/main/java/org/yzr/vo/PackageViewModel.java +++ b/src/main/java/org/yzr/vo/PackageViewModel.java @@ -1,7 +1,6 @@ package org.yzr.vo; import com.alibaba.fastjson.JSON; -import lombok.Getter; import org.apache.commons.io.FileUtils; import org.springframework.util.StringUtils; import org.yzr.model.Package; @@ -14,7 +13,6 @@ import java.util.List; import java.util.Map; -@Getter public class PackageViewModel { private String downloadURL; private String safeDownloadURL; @@ -60,7 +58,7 @@ public class PackageViewModel { this.installURL = pathManager.getPackageResourceURL(aPackage, false) + aPackage.getFileName(); } this.previewURL = pathManager.getBaseURL(false) + "s/" + aPackage.getApp().getShortCode() + "?id=" + aPackage.getId(); - if (this.isIOS()) { + if (this.isiOS()) { if (aPackage.getProvision() == null) { this.type = "内测版"; } else { @@ -95,4 +93,75 @@ public class PackageViewModel { this.message = message; } + public String getDownloadURL() { + return downloadURL; + } + + public String getSafeDownloadURL() { + return safeDownloadURL; + } + + public String getIconURL() { + return iconURL; + } + + public String getInstallURL() { + return installURL; + } + + public String getPreviewURL() { + return previewURL; + } + + public String getId() { + return id; + } + + public String getVersion() { + return version; + } + + public String getBundleID() { + return bundleID; + } + + public String getName() { + return name; + } + + public long getCreateTime() { + return createTime; + } + + public String getBuildVersion() { + return buildVersion; + } + + public String getDisplaySize() { + return displaySize; + } + + public String getDisplayTime() { + return displayTime; + } + + public boolean isiOS() { + return iOS; + } + + public String getType() { + return type; + } + + public List getDevices() { + return devices; + } + + public int getDeviceCount() { + return deviceCount; + } + + public String getMessage() { + return message; + } } diff --git a/src/main/java/org/yzr/vo/WebHookViewModel.java b/src/main/java/org/yzr/vo/WebHookViewModel.java index 5715283..4eeabee 100644 --- a/src/main/java/org/yzr/vo/WebHookViewModel.java +++ b/src/main/java/org/yzr/vo/WebHookViewModel.java @@ -1,8 +1,5 @@ package org.yzr.vo; -import lombok.Data; - -@Data public class WebHookViewModel { private String id; @@ -14,4 +11,44 @@ public class WebHookViewModel { private String type; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } }